diff --git a/.github/workflows/format-lint-test.yml b/.github/workflows/format-lint-test.yml index 26a5f8e..3f7b922 100644 --- a/.github/workflows/format-lint-test.yml +++ b/.github/workflows/format-lint-test.yml @@ -28,6 +28,7 @@ jobs: run: npm run lint:check test: + timeout-minutes: 10 runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -36,5 +37,17 @@ jobs: node-version: '20' - name: Install dependencies run: npm ci + - name: Build extension + run: npm run build + - name: Install Playwright Browsers + run: npx playwright install --with-deps chromium - name: Run tests run: npm run test + + # Upload test results on failure + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 diff --git a/.gitignore b/.gitignore index f06235c..1e5f630 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ node_modules dist +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/build.js b/build.js index bd2aef9..7df6abc 100755 --- a/build.js +++ b/build.js @@ -22,7 +22,7 @@ const context = await esbuild.context({ ], outdir: "dist", target: ["es2020"], - loader: { ".js": "jsx" }, + loader: { ".js": "jsx", ".ttf": "file" }, plugins: [ { name: "clean-dist", diff --git a/package-lock.json b/package-lock.json index cb3197c..4e459fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ }, "devDependencies": { "@biomejs/biome": "1.8.3", + "@playwright/test": "^1.45.3", "@types/chrome": "^0.0.269", "@types/node": "^20.14.12", "@types/react": "^18.3.3", @@ -733,6 +734,21 @@ "node": ">=14" } }, + "node_modules/@playwright/test": { + "version": "1.45.3", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.45.3.tgz", + "integrity": "sha512-UKF4XsBfy+u3MFWEH44hva1Q8Da28G6RFtR2+5saw+jgAFQV5yYnB1fu68Mz7fO+5GJF3wgwAIs0UelU8TxFrA==", + "dev": true, + "dependencies": { + "playwright": "1.45.3" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@radix-ui/number": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.0.tgz", @@ -2579,6 +2595,50 @@ "node": ">= 6" } }, + "node_modules/playwright": { + "version": "1.45.3", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.45.3.tgz", + "integrity": "sha512-QhVaS+lpluxCaioejDZ95l4Y4jSFCsBvl2UZkpeXlzxmqS+aABr5c82YmfMHrL6x27nvrvykJAFpkzT2eWdJww==", + "dev": true, + "dependencies": { + "playwright-core": "1.45.3" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.45.3", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.45.3.tgz", + "integrity": "sha512-+ym0jNbcjikaOwwSZycFbwkWgfruWvYlJfThKYAlImbxUgdWFO2oW70ojPm4OpE4t6TAo2FY/smM+hpVTtkhDA==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/postcss": { "version": "8.4.40", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.40.tgz", diff --git a/package.json b/package.json index 355f498..0159ce6 100644 --- a/package.json +++ b/package.json @@ -6,10 +6,11 @@ "lint:check": "biome lint .", "format:check": "biome format .", "format:fix": "biome format --write .", - "test": "echo \"For now, we don't have any tests.\"" + "test": "PW_TEST_HTML_REPORT_OPEN='never' npx playwright test" }, "devDependencies": { "@biomejs/biome": "1.8.3", + "@playwright/test": "^1.45.3", "@types/chrome": "^0.0.269", "@types/node": "^20.14.12", "@types/react": "^18.3.3", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..e4d6c27 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,78 @@ +import { defineConfig, devices } from "@playwright/test"; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// import dotenv from 'dotenv'; +// 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://127.0.0.1:3000', + + /* 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: 'npm run start', + // url: 'http://127.0.0.1:3000', + // reuseExistingServer: !process.env.CI, + // }, +}); diff --git a/src/css/Inter.ttf b/src/css/Inter.ttf new file mode 100644 index 0000000..e724708 Binary files /dev/null and b/src/css/Inter.ttf differ diff --git a/src/css/tailwind.css b/src/css/tailwind.css index 95d8cab..ff78ba8 100644 --- a/src/css/tailwind.css +++ b/src/css/tailwind.css @@ -78,4 +78,8 @@ @apply bg-background text-foreground; font-feature-settings: "rlig" 1, "calt" 1; } + @font-face { + font-family: "Inter"; + src: url("./Inter.ttf") format("truetype"); + } } diff --git a/src/newtab/App.tsx b/src/newtab/App.tsx index 9a9e212..8f7c40f 100644 --- a/src/newtab/App.tsx +++ b/src/newtab/App.tsx @@ -50,7 +50,7 @@ export default function App() { }, [todayUsage]); return ( -
+
diff --git a/tailwind.config.ts b/tailwind.config.ts index 0bf7a61..3aae5a1 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -54,7 +54,7 @@ module.exports = { sm: "calc(var(--radius) - 4px)", }, fontFamily: { - sans: ["var(--font-sans)", ...fontFamily.sans], + sans: ["Inter", ...fontFamily.sans], }, keyframes: { "accordion-down": { diff --git a/tests/example.spec.ts b/tests/example.spec.ts new file mode 100644 index 0000000..68ea78c --- /dev/null +++ b/tests/example.spec.ts @@ -0,0 +1,46 @@ +import { test as base, type BrowserContext } from "@playwright/test"; +import { chromium } from "playwright"; +import path from "node:path"; + +// @ts-ignore: stop typescript from bitching about import.meta +const __dirname = path.dirname(import.meta.filename); + +const test = base.extend<{ context: BrowserContext; extensionId: string }>({ + // biome-ignore lint: not use what this object destructuring is for + context: async ({}, use) => { + const pathToExtension = path.join(__dirname, "../dist"); + const context = await chromium.launchPersistentContext("", { + headless: false, + args: [ + "--headless=new", + `--disable-extensions-except=${pathToExtension}`, + `--load-extension=${pathToExtension}`, + ], + }); + await use(context); + await context.close(); + }, + extensionId: async ({ context }, use) => { + let [background] = context.serviceWorkers(); + if (!background) { + background = await context.waitForEvent("backgroundpage"); + } + const exntesionId = background.url().split("/")[2]; + await use(exntesionId); + }, +}); + +const expect = test.expect; + +test("Extension in New Tab page", async ({ page }) => { + await page.goto("https://playwright.dev/"); + await page.waitForTimeout(3000); + await page.goto("chrome://newtab"); + await expect(page).toHaveTitle("New Tab"); + await expect(page).toHaveScreenshot({ + mask: [ + page.locator("section > div:last-child > div:first-child svg"), + page.locator("section > div:first-child ul li button img"), + ], + }); +}); diff --git a/tests/example.spec.ts-snapshots/Extension-in-New-Tab-page-1-chromium-linux.png b/tests/example.spec.ts-snapshots/Extension-in-New-Tab-page-1-chromium-linux.png new file mode 100644 index 0000000..6a5318b Binary files /dev/null and b/tests/example.spec.ts-snapshots/Extension-in-New-Tab-page-1-chromium-linux.png differ