Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setup for playwright tests, run unit tests on PR #340

Merged
merged 27 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Playwright Tests

on:
push:
branches: [master]
pull_request:
branches: [master]

env:
URL: "https://deploy-preview-${{ github.event.number }}.muckcloud.com"
PLAYWRIGHT_TEST_BASE_URL: "https://deploy-preview-${{ github.event.number }}.muckcloud.com"
NODE_ENV: staging

jobs:
wait:
runs-on: ubuntu-latest

steps:
- uses: cygnetdigital/[email protected]
with:
url: ${{ env.URL }}
responseCode: "200"
timeout: 120000
interval: 3000

test:
timeout-minutes: 60
runs-on: ubuntu-latest
needs: wait

steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18

- name: Install dependencies
run: npm ci

- name: Install Playwright
run: npx playwright install --with-deps

- name: Run Playwright tests
run: npx playwright test
26 changes: 26 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions

name: Unit tests

on:
push:
branches: [master]
pull_request:
branches: [master]

jobs:
test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Use Node.js 18.x
uses: actions/setup-node@v3
with:
node-version: "18.x"
- run: npm ci
- run: npm run build
env:
NODE_ENV: production
- run: npm test
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ public/assets/
# Local test env file
.env.test
.env.sentry-build-plugin
playwright-report
test-results

# local fixtures, everyone should generate their own
tests/fixtures/development.json

.vscode

Expand Down
4 changes: 2 additions & 2 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
export default {
extensionsToTreatAsEsm: [".svelte"],
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/src/$1",
"^@/(.*)$": "<rootDir>/$1",
},
moduleFileExtensions: ["js", "svelte"],
modulePaths: ["src"],
rootDir: "src",
setupFiles: ["dotenv/config"],
testEnvironment: "jsdom",
transform: {
Expand Down
23 changes: 23 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 8 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"webpack-dev-server": "^4.15.1"
},
"devDependencies": {
"@playwright/test": "^1.39.0",
"@storybook/addon-essentials": "^7.4.5",
"@storybook/addon-interactions": "^7.4.5",
"@storybook/addon-links": "^7.4.5",
Expand All @@ -68,6 +69,7 @@
"jest-environment-jsdom": "^29.7.0",
"msw": "^1.2.3",
"msw-storybook-addon": "^1.8.0",
"netlify-plugin-playwright-cache": "^0.0.1",
"playwright": "^1.39.0",
"prettier": "^3.0.2",
"prettier-plugin-svelte": "^3.0.3",
Expand All @@ -83,16 +85,17 @@
"build-staging": "cross-env NODE_ENV=staging webpack",
"build-serve": "cross-env NODE_ENV=production webpack && serve public -l 80 --single",
"build-analyze": "cross-env NODE_ENV=production-analyze webpack",
"build-storybook": "storybook build",
"dev": "concurrently \"npm:dev-app\" \"npm:dev-embed\"",
"dev-app": "cross-env NODE_ENV=development SUPPRESS_WARNINGS=1 webpack serve --config webpack.app.config.js",
"dev-embed": "cross-env NODE_ENV=development webpack --config webpack.embed.config.js",
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
"serve": "serve public -l 80 --single",
"watch-app": "cross-env NODE_ENV=development webpack watch --config webpack.app.config.js",
"watch": "concurrently npm:serve npm:dev-embed npm:watch-app",
"test-watch": "jest --watchAll",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build"
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
"test-watch": "jest --watchAll",
"test:browser": "playwright test",
"watch": "concurrently npm:serve npm:dev-embed npm:watch-app",
"watch-app": "cross-env NODE_ENV=development webpack watch --config webpack.app.config.js"
},
"engine": 18,
"browserslist": "> 0.25%, not dead",
Expand Down
65 changes: 65 additions & 0 deletions playwright.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { defineConfig, devices } from "@playwright/test";
import dotenv from "dotenv";

const environment = process.env.NODE_ENV || "development";

dotenv.config({
path: environment === "development" ? ".env" : `.env.${environment}`,
});

if (environment === "development") {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
}

export default defineConfig({
// Look for test files in the "tests" directory, relative to this configuration file.
testDir: "tests",

// Run all tests 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,

// Reporter to use
reporter: "html",

workers: process.env.CI ? 1 : undefined,

use: {
// Base URL to use in actions like `await page.goto('/')`.
baseURL: process.env.URL || "https://www.dev.documentcloud.org",

// Collect trace when retrying the failed test.
trace: "on-first-retry",
},

// Options specific to each project.
projects: [
{
name: "chromium",
use: devices["Desktop Chrome"],
},
{
name: "firefox",
use: devices["Desktop Firefox"],
},
{
name: "webkit",
use: devices["Desktop Safari"],
},
/* todo configure tests for mobile
{
name: "Mobile Chrome",
use: devices["Pixel 5"],
},
{
name: "Mobile Safari",
use: devices["iPhone 12"],
},
*/
],
});
22 changes: 22 additions & 0 deletions plugins/test/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// netlify plugin to run playwright on deploy previews

export async function onSuccess({ utils }) {
console.log("Installing Playwright dependencies");
await utils.run("playwright", ["install"]).catch((err) => {
utils.build.failBuild(err);
});

console.log("Running Playwright tests");
result = await utils.run("playwright", ["test"]).catch((err) => {
utils.status.show({
title: "Playwright test failed",
summary: err.toString(),
});
utils.build.failPlugin(err);
});

utils.status.show({
title: "Playwright tests completed.",
summary: "",
});
}
1 change: 1 addition & 0 deletions plugins/test/manifest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
name: netlify-plugin-playwright
2 changes: 1 addition & 1 deletion src/pages/app/Anonymous.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
</div>
<div class="text">
<p>
{$_("anonymous.p1", { values: { n: $search.results.count } })}
{$_("anonymous.p1", { values: { n: $search?.results?.count ?? 0 } })}
</p>
<p>
{@html $_("anonymous.p2")}
Expand Down
2 changes: 1 addition & 1 deletion src/pages/app/Documents.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@
on:files={showUploadModal}
disabled={embed || !$orgsAndUsers.loggedIn || !$orgsAndUsers.isVerified}
>
{#if !$orgsAndUsers.loggedIn && $search.params.query === "" && !anonymousClosed}
{#if !$orgsAndUsers.loggedIn && $search.params?.query === "" && !anonymousClosed}
<Anonymous bind:closed={anonymousClosed} />
{:else}
{#each $documents.documents as document (document.id)}
Expand Down
9 changes: 9 additions & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# End-to-end tests

This directory includes [Playwright](https://playwright.dev) tests that run in a headless browser against a running version of the site. To run locally, start a full instance (Squarelet, the DocumentCloud API and frontend) and set the `URL` environment variable. For example:

```sh
URL=https://www.dev.documentcloud.org npx playwright test
```

Netlify will automatically run this against any pull request using a deploy preview, and it will set the `URL` environment variable to the correct target.
12 changes: 12 additions & 0 deletions tests/anonymous/manager/app.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// @ts-check

import { test, expect } from "@playwright/test";

test("basic manager rendering", async ({ page }) => {
await page.goto("/app");

const url = new URL(page.url());
expect(url.pathname).toBe("/app");

await expect(page).toHaveTitle("DocumentCloud");
});
9 changes: 9 additions & 0 deletions tests/anonymous/pages/home.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// @ts-check

import { test, expect } from "@playwright/test";

test("basic homepage test", async ({ page }) => {
await page.goto("/home");

await expect(page).toHaveTitle("Home | DocumentCloud");
});
62 changes: 62 additions & 0 deletions tests/anonymous/viewer/document.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// @ts-check
import fs from "node:fs/promises";
import { test as base, expect } from "@playwright/test";

const {
DC_BASE = "https://api.dev.documentcloud.org",
NODE_ENV = "development",
} = process.env;

const test = base.extend({
document: async ({ page }, use) => {
const filename = new URL(
`../../fixtures/${NODE_ENV}.json`,
import.meta.url,
);

const documents = await fs
.readFile(filename)
.then((s) => JSON.parse(s.toString()));

await use(documents[0]);
},
});

test.describe("document tests", () => {
test("basic document test", async ({ page, document }) => {
// canonical will point to a URL that might not exist on staging
const path = new URL(document.canonical_url).pathname;
await page.goto(path).catch(console.error);

expect(new URL(page.url()).pathname).toBe(path);

await expect(page.locator(".sidebar").getByRole("heading")).toHaveText(
document.title,
);

await page.getByRole("link", { name: "Original Document (PDF) »" }).click();

await expect(page.locator("h1")).toHaveText(document.title);

await page.getByRole("link", { name: "p. 1" }).click();

expect(new URL(page.url()).hash).toEqual("#document/p1");

await page
.locator("div")
.filter({ hasText: /^DocumentPlain TextThumbnailSearch Results$/ })
.getByRole("combobox")
.selectOption("text");

// check that text view loaded
/*
await expect(page.locator(".text").first()).toHaveText(
text.pages[0].contents,
);
*/

// switch to thumbnail view, click the first image
await page.getByRole("combobox").selectOption("thumbnail");
await page.locator("img").first().click();
});
});
File renamed without changes.
Loading