diff --git a/apps/partner-sas/.gitignore b/apps/partner-sas/.gitignore index 3320db616..fc1b6f145 100644 --- a/apps/partner-sas/.gitignore +++ b/apps/partner-sas/.gitignore @@ -46,4 +46,11 @@ next-env.d.ts .yarn/build-state.yml .yarn/install-state.gz .pnp.* -.yarn/releases \ No newline at end of file +.yarn/releases + +# Playwright +node_modules/ +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/apps/partner-sas/netlify.toml b/apps/partner-sas/netlify.toml index d1d407a3a..8d2f7bab5 100644 --- a/apps/partner-sas/netlify.toml +++ b/apps/partner-sas/netlify.toml @@ -1,13 +1,13 @@ [build] -command = "yarn build:sas" +command = "yarn test && yarn build:sas" publish = "apps/partner-sas/.next" ignore = "git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF apps/partner-sas packages/common packages/trpc packages/design-system packages/typescript-config" [context.branch-deploy] -command = "yarn build:sas" +command = "yarn test && yarn build:sas" [context.deploy-preview] -command = "yarn build:sas" +command = "yarn test && yarn build:sas" [build.environment] # set TERM variable for terminal output diff --git a/apps/partner-sas/package.json b/apps/partner-sas/package.json index f56bcc11f..61cc0a254 100644 --- a/apps/partner-sas/package.json +++ b/apps/partner-sas/package.json @@ -9,7 +9,10 @@ "start": "node .next/standalone/server.js", "lint": "next lint --max-warnings 0 && tsc --noEmit", "lint:fix": "next lint --fix && tsc --noEmit", - "check-types": "tsc --noEmit" + "check-types": "tsc --noEmit", + "test": "vitest run --passWithNoTests", + "test:watch": "vitest", + "test:e2e": "playwright test" }, "dependencies": { "@netlify/plugin-nextjs": "^5.11.2", @@ -22,6 +25,7 @@ "devDependencies": { "@eslint/eslintrc": "^3.3.1", "@eslint/js": "^9.26.0", + "@playwright/test": "^1.53.1", "@scandic-hotels/common": "workspace:*", "@scandic-hotels/typescript-config": "workspace:*", "@types/node": "^20", @@ -36,7 +40,8 @@ "eslint-plugin-simple-import-sort": "^12.1.1", "graphql-tag": "^2.12.6", "typescript": "5.8.3", - "typescript-plugin-css-modules": "^5.1.0" + "typescript-plugin-css-modules": "^5.1.0", + "vitest": "^3.2.4" }, "engines": { "node": "22" diff --git a/apps/partner-sas/playwright.config.ts b/apps/partner-sas/playwright.config.ts new file mode 100644 index 000000000..e3ba29f89 --- /dev/null +++ b/apps/partner-sas/playwright.config.ts @@ -0,0 +1,79 @@ +import { defineConfig, devices } from "@playwright/test" + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// import dotenv from 'dotenv'; +// import path from 'path'; +// dotenv.config({ path: path.resolve(__dirname, '.env') }); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: "./tests", + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: "html", + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: "http://localhost:3001", + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: "on-first-retry", + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: "chromium", + use: { ...devices["Desktop Chrome"] }, + }, + + { + name: "firefox", + use: { ...devices["Desktop Firefox"] }, + }, + + { + name: "webkit", + use: { ...devices["Desktop Safari"] }, + }, + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + webServer: { + command: "yarn dev", + url: "http://localhost:3001", + reuseExistingServer: !process.env.CI, + }, +}) diff --git a/apps/partner-sas/tests/dummy.spec.ts b/apps/partner-sas/tests/dummy.spec.ts new file mode 100644 index 000000000..02f5c17ba --- /dev/null +++ b/apps/partner-sas/tests/dummy.spec.ts @@ -0,0 +1,7 @@ +import { expect, test } from "@playwright/test" + +test("has text", async ({ page }) => { + await page.goto("/") + + await expect(page.getByText(/hello world/i)).toBeVisible() +}) diff --git a/apps/partner-sas/vitest-setup.ts b/apps/partner-sas/vitest-setup.ts new file mode 100644 index 000000000..d7609e016 --- /dev/null +++ b/apps/partner-sas/vitest-setup.ts @@ -0,0 +1,30 @@ +import { vi } from "vitest" + +process.env.TZ = "UTC" + +vi.mock("next/navigation", () => ({ + useRouter: vi.fn(), + usePathname: vi.fn().mockReturnValue("/"), + useParams: vi.fn().mockReturnValue({ lang: "en" }), +})) + +Object.defineProperty(window, "matchMedia", { + writable: true, + value: vi.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: vi.fn(), // deprecated + removeListener: vi.fn(), // deprecated + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + })), +}) + +Object.defineProperty(window, "CSS", { + writable: true, + value: { + escape: vi.fn(), + }, +}) diff --git a/apps/partner-sas/vitest.config.ts b/apps/partner-sas/vitest.config.ts new file mode 100644 index 000000000..1d7de62c1 --- /dev/null +++ b/apps/partner-sas/vitest.config.ts @@ -0,0 +1,26 @@ +import react from "@vitejs/plugin-react" +import tsconfigPaths from "vite-tsconfig-paths" +import { defineConfig } from "vitest/config" + +export default defineConfig({ + plugins: [ + tsconfigPaths(), + react({ + babel: { + plugins: [ + [ + "formatjs", + { + idInterpolationPattern: "[sha512:contenthash:base64:6]", + }, + ], + ], + }, + }), + ], + test: { + environment: "jsdom", + setupFiles: ["./vitest-setup.ts"], + include: ["**/*.{test}.?(c|m)[jt]s?(x)"], + }, +}) diff --git a/yarn.lock b/yarn.lock index 20585d3c0..f395ec36d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4516,6 +4516,17 @@ __metadata: languageName: node linkType: hard +"@playwright/test@npm:^1.53.1": + version: 1.53.1 + resolution: "@playwright/test@npm:1.53.1" + dependencies: + playwright: "npm:1.53.1" + bin: + playwright: cli.js + checksum: 10c0/f2ef7899ca6bc178c9f2ba6c8633d0bbeb5ba135048e9df01ecb949c6f743811ba5ef76d495f619454074c81dbfa28be12e4c0a1224bb2af0d4cb403182c716f + languageName: node + linkType: hard + "@pnpm/config.env-replace@npm:^1.1.0": version: 1.1.0 resolution: "@pnpm/config.env-replace@npm:1.1.0" @@ -6882,6 +6893,7 @@ __metadata: "@eslint/eslintrc": "npm:^3.3.1" "@eslint/js": "npm:^9.26.0" "@netlify/plugin-nextjs": "npm:^5.11.2" + "@playwright/test": "npm:^1.53.1" "@scandic-hotels/booking-flow": "workspace:*" "@scandic-hotels/common": "workspace:*" "@scandic-hotels/design-system": "workspace:*" @@ -6902,6 +6914,7 @@ __metadata: react-dom: "npm:^19.0.0" typescript: "npm:5.8.3" typescript-plugin-css-modules: "npm:^5.1.0" + vitest: "npm:^3.2.4" languageName: unknown linkType: soft @@ -13754,6 +13767,16 @@ __metadata: languageName: node linkType: hard +"fsevents@npm:2.3.2": + version: 2.3.2 + resolution: "fsevents@npm:2.3.2" + dependencies: + node-gyp: "npm:latest" + checksum: 10c0/be78a3efa3e181cda3cf7a4637cb527bcebb0bd0ea0440105a3bb45b86f9245b307dc10a2507e8f4498a7d4ec349d1910f4d73e4d4495b16103106e07eee735b + conditions: os=darwin + languageName: node + linkType: hard + "fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": version: 2.3.3 resolution: "fsevents@npm:2.3.3" @@ -13764,6 +13787,15 @@ __metadata: languageName: node linkType: hard +"fsevents@patch:fsevents@npm%3A2.3.2#optional!builtin": + version: 2.3.2 + resolution: "fsevents@patch:fsevents@npm%3A2.3.2#optional!builtin::version=2.3.2&hash=df0bf1" + dependencies: + node-gyp: "npm:latest" + conditions: os=darwin + languageName: node + linkType: hard + "fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": version: 2.3.3 resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" @@ -18169,6 +18201,30 @@ __metadata: languageName: node linkType: hard +"playwright-core@npm:1.53.1": + version: 1.53.1 + resolution: "playwright-core@npm:1.53.1" + bin: + playwright-core: cli.js + checksum: 10c0/8780552740741b94c346373ab6f949e9a44d3df54016b12123da9fe2f5fb60c1838197642916789b0a2ffb567e4ba0089f2e57d496bef7e460ddc4526f9b3b0f + languageName: node + linkType: hard + +"playwright@npm:1.53.1": + version: 1.53.1 + resolution: "playwright@npm:1.53.1" + dependencies: + fsevents: "npm:2.3.2" + playwright-core: "npm:1.53.1" + dependenciesMeta: + fsevents: + optional: true + bin: + playwright: cli.js + checksum: 10c0/3dcbcd3791a7f0d1007db4d3126c8136258a2002c2fbfc8b840086b64cbc1fb628b2e25dd3b345d685fb27ba39790ab0f4ce81a8faade7dc748af3a63bdf3550 + languageName: node + linkType: hard + "polished@npm:^4.2.2": version: 4.3.1 resolution: "polished@npm:4.3.1"