Skip to content

Commit

Permalink
E2E tests refactoring (#1318)
Browse files Browse the repository at this point in the history
* Adds test todos

* Can't seem to change locales

* WIP playwright test refactoring

* jest-playwright cleanup

* Test fixes

* Test fixes

* More test fixes

* WIP: Testing fixes

* More test fixes

* Removes unused files

* Installs missing browsers for e2e

* ts-node fixes

* ts-check fixes

* Type fixes

* Fixes e2e

* FFS

* Renamex webhook snapshot

* Fixes webhook cross-platform

* Renamed webhook snapshot

* Apply suggestions from code review

Co-authored-by: Max Schmitt <max@schmitt.mx>

* Removes kont dependency

* Cleanup playwright options

* Next.js cache optimizations on CI

* Uses cache on e2e as well

* Fixme is introducing side-effects

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
Co-authored-by: Max Schmitt <max@schmitt.mx>
  • Loading branch information
4 people committed Dec 15, 2021
1 parent 972402b commit e6f71c8
Show file tree
Hide file tree
Showing 21 changed files with 527 additions and 853 deletions.
6 changes: 5 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ jobs:
uses: actions/cache@v2
with:
path: ${{ github.workspace }}/.next/cache
key: ${{ runner.os }}-nextjs
# Generate a new cache whenever packages or source files change.
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }}
# If source files changed but packages didn't, rebuild from a prior cache.
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
- run: yarn prisma migrate deploy
- run: yarn test
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ jobs:
uses: actions/cache@v2
with:
path: ${{ github.workspace }}/.next/cache
key: ${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}-nextjs
# Generate a new cache whenever packages or source files change.
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }}
# If source files changed but packages didn't, rebuild from a prior cache.
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
- run: yarn prisma migrate deploy
- run: yarn db-seed
Expand All @@ -71,7 +75,7 @@ jobs:
key: cache-playwright-${{ hashFiles('**/yarn.lock') }}
- name: Install playwright deps
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: yarn playwright install-deps
run: yarn playwright install --with-deps

- run: yarn test-playwright

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
.nyc_output
playwright/videos
playwright/screenshots
playwright/artifacts

# next.js
/.next/
Expand Down
2 changes: 1 addition & 1 deletion components/Shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ export default function Shell(props: {
<Toaster position="bottom-right" />
</div>

<div className="flex h-screen overflow-hidden bg-gray-100">
<div className="flex h-screen overflow-hidden bg-gray-100" data-testid="dashboard-shell">
<div className="hidden md:flex lg:flex-shrink-0">
<div className="flex flex-col w-14 lg:w-56">
<div className="flex flex-col flex-1 h-0 bg-white border-r border-gray-200">
Expand Down
35 changes: 0 additions & 35 deletions jest.playwright.config.js

This file was deleted.

12 changes: 4 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,23 @@
"db-up": "docker-compose up -d",
"db-migrate": "yarn prisma migrate dev",
"db-deploy": "yarn prisma migrate deploy",
"db-seed": "yarn ts-node scripts/seed.ts",
"db-seed": "ts-node scripts/seed.ts",
"db-nuke": "docker-compose down --volumes --remove-orphans",
"db-setup": "run-s db-up db-migrate db-seed",
"db-reset": "run-s db-nuke db-setup",
"deploy": "run-s build db-deploy",
"dx": "env-cmd run-s db-setup dev",
"test": "jest",
"test-playwright": "jest --config jest.playwright.config.js",
"test-playwright": "playwright test",
"test-codegen": "yarn playwright codegen http://localhost:3000",
"type-check": "tsc --pretty --noEmit",
"build": "next build",
"start": "next start",
"ts-node": "ts-node --compiler-options \"{\\\"module\\\":\\\"commonjs\\\"}\"",
"postinstall": "prisma generate",
"pre-commit": "lint-staged",
"lint": "eslint . --ext .ts,.js,.tsx,.jsx",
"prepare": "husky install",
"check-changed-files": "yarn ts-node scripts/ts-check-changed-files.ts"
"check-changed-files": "ts-node scripts/ts-check-changed-files.ts"
},
"engines": {
"node": ">=14.x",
Expand Down Expand Up @@ -105,6 +104,7 @@
},
"devDependencies": {
"@microsoft/microsoft-graph-types-beta": "0.15.0-preview",
"@playwright/test": "^1.17.1",
"@tailwindcss/forms": "^0.4.0",
"@trivago/prettier-plugin-sort-imports": "2.0.4",
"@types/accept-language-parser": "1.5.2",
Expand Down Expand Up @@ -134,13 +134,9 @@
"eslint-plugin-react-hooks": "^4.3.0",
"husky": "^7.0.1",
"jest": "^26.0.0",
"jest-playwright": "^0.0.1",
"jest-playwright-preset": "^1.7.0",
"kont": "^0.5.1",
"lint-staged": "^11.1.2",
"mockdate": "^3.0.5",
"npm-run-all": "^4.1.5",
"playwright": "^1.16.2",
"postcss": "^8.4.4",
"prettier": "^2.3.2",
"prisma": "^2.30.2",
Expand Down
29 changes: 21 additions & 8 deletions pages/event-types/[type].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import React, { useEffect, useState } from "react";
import { useForm, Controller } from "react-hook-form";
import { FormattedNumber, IntlProvider } from "react-intl";
import { useMutation } from "react-query";
import Select, { OptionTypeBase } from "react-select";
import Select from "react-select";

import { StripeData } from "@ee/lib/stripe/server";

Expand Down Expand Up @@ -59,6 +59,12 @@ import * as RadioArea from "@components/ui/form/radio-area";
dayjs.extend(utc);
dayjs.extend(timezone);

type OptionTypeBase = {
label: string;
value: LocationType;
disabled?: boolean;
};

const addDefaultLocationOptions = (
defaultLocations: OptionTypeBase[],
locationOptions: OptionTypeBase[]
Expand Down Expand Up @@ -295,8 +301,10 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
classNamePrefix="react-select"
className="flex-1 block w-full min-w-0 border border-gray-300 rounded-sm react-select-container focus:ring-primary-500 focus:border-primary-500 sm:text-sm"
onChange={(e) => {
locationFormMethods.setValue("locationType", e?.value);
openLocationModal(e?.value);
if (e?.value) {
locationFormMethods.setValue("locationType", e.value);
openLocationModal(e.value);
}
}}
/>
</div>
Expand Down Expand Up @@ -461,15 +469,15 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
centered
title={t("event_type_title", { eventTypeTitle: eventType.title })}
heading={
<div className="relative group cursor-pointer" onClick={() => setEditIcon(false)}>
<div className="relative cursor-pointer group" onClick={() => setEditIcon(false)}>
{editIcon ? (
<>
<h1
style={{ fontSize: 22, letterSpacing: "-0.0009em" }}
className="inline pl-0 text-gray-900 focus:text-black group-hover:text-gray-500">
{eventType.title}
</h1>
<PencilIcon className="-mt-1 ml-1 inline w-4 h-4 text-gray-700 group-hover:text-gray-500" />
<PencilIcon className="inline w-4 h-4 ml-1 -mt-1 text-gray-700 group-hover:text-gray-500" />
</>
) : (
<div style={{ marginBottom: -11 }}>
Expand All @@ -478,7 +486,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
autoFocus
style={{ top: -6, fontSize: 22 }}
required
className="w-full relative pl-0 h-10 text-gray-900 bg-transparent border-none cursor-pointer focus:text-black hover:text-gray-700 focus:ring-0 focus:outline-none"
className="relative w-full h-10 pl-0 text-gray-900 bg-transparent border-none cursor-pointer focus:text-black hover:text-gray-700 focus:ring-0 focus:outline-none"
placeholder={t("quick_chat")}
{...formMethods.register("title")}
defaultValue={eventType.title}
Expand Down Expand Up @@ -639,6 +647,9 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
value={asStringOrUndefined(eventType.schedulingType)}
options={schedulingTypeOptions}
onChange={(val) => {
// FIXME
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
formMethods.setValue("schedulingType", val);
}}
/>
Expand Down Expand Up @@ -1154,8 +1165,10 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
classNamePrefix="react-select"
className="flex-1 block w-full min-w-0 my-4 border border-gray-300 rounded-sm react-select-container focus:ring-primary-500 focus:border-primary-500 sm:text-sm"
onChange={(val) => {
locationFormMethods.setValue("locationType", val.value);
setSelectedLocation(val);
if (val) {
locationFormMethods.setValue("locationType", val.value);
setSelectedLocation(val);
}
}}
/>
)}
Expand Down
2 changes: 1 addition & 1 deletion pages/getting-started.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ export default function Onboarding(props: inferSSRProps<typeof getServerSideProp
}

return (
<div className="min-h-screen bg-brand">
<div className="min-h-screen bg-brand" data-testid="onboarding">
<Head>
<title>Cal.com - {t("getting_started")}</title>
<link rel="icon" href="/favicon.ico" />
Expand Down
36 changes: 36 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { PlaywrightTestConfig, devices } from "@playwright/test";

const config: PlaywrightTestConfig = {
forbidOnly: !!process.env.CI,
testDir: "playwright",
timeout: 60_000,
retries: process.env.CI ? 3 : 0,
globalSetup: require.resolve("./playwright/lib/globalSetup"),
use: {
baseURL: "http://localhost:3000",
locale: "en-US",
trace: "on-first-retry",
headless: !!process.env.CI || !!process.env.PLAYWRIGHT_HEADLESS,
contextOptions: {
recordVideo: {
dir: "playwright/videos",
},
},
},
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
/* {
name: "firefox",
use: { ...devices["Desktop Firefox"] },
},
{
name: "webkit",
use: { ...devices["Desktop Safari"] },
}, */
],
};

export default config;
48 changes: 19 additions & 29 deletions playwright/booking-pages.test.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,32 @@
import { kont } from "kont";
import { test, expect } from "@playwright/test";

import { pageProvider } from "./lib/pageProvider";
import { todo } from "./lib/testUtils";

jest.setTimeout(60e3);
if (process.env.CI) {
jest.retryTimes(3);
}

describe("free user", () => {
const ctx = kont()
.useBeforeEach(pageProvider({ path: "/free" }))
.done();

test("only one visible event", async () => {
const { page } = ctx;
await expect(page).toHaveSelector(`[href="/free/30min"]`);
await expect(page).not.toHaveSelector(`[href="/free/60min"]`);
test.describe("free user", () => {
test.beforeEach(async ({ page }) => {
await page.goto("/free");
});
test("only one visible event", async ({ page }) => {
await expect(page.locator(`[href="/free/30min"]`)).toBeVisible();
await expect(page.locator(`[href="/free/60min"]`)).not.toBeVisible();
});

test.todo("`/free/30min` is bookable");
todo("`/free/30min` is bookable");

test.todo("`/free/60min` is not bookable");
todo("`/free/60min` is not bookable");
});

describe("pro user", () => {
const ctx = kont()
.useBeforeEach(pageProvider({ path: "/pro" }))
.done();
test.describe("pro user", () => {
test.beforeEach(async ({ page }) => {
await page.goto("/pro");
});

test("pro user's page has at least 2 visible events", async () => {
const { page } = ctx;
test("pro user's page has at least 2 visible events", async ({ page }) => {
const $eventTypes = await page.$$("[data-testid=event-types] > *");

expect($eventTypes.length).toBeGreaterThanOrEqual(2);
});

test("book an event first day in next month", async () => {
const { page } = ctx;
test("book an event first day in next month", async ({ page }) => {
// Click first event type
await page.click('[data-testid="event-type-link"]');
// Click [data-testid="incrementMonth"]
Expand All @@ -58,7 +48,7 @@ describe("pro user", () => {
});
});

test.todo("Can reschedule the recently created booking");
todo("Can reschedule the recently created booking");

test.todo("Can cancel the recently created booking");
todo("Can cancel the recently created booking");
});

0 comments on commit e6f71c8

Please sign in to comment.