Skip to content

Commit

Permalink
web: optimize tests by ~120% (streetwriters#1018)
Browse files Browse the repository at this point in the history
This is mainly done via sharding, caching & reducing total work:
1. `terser` is turned off when generating test build
2. `nx` distributed cache allows reusing build outputs
3. `playwright` sharding allows running tests in parallel

This can further be improved by using `swc` & `esbuild` during build
  • Loading branch information
thecodrr authored Sep 21, 2022
1 parent e347922 commit 6d75476
Show file tree
Hide file tree
Showing 14 changed files with 309 additions and 96 deletions.
21 changes: 17 additions & 4 deletions .github/workflows/core.tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,33 @@ jobs:

steps:
- uses: actions/checkout@v3
- name: Use Node.js 16.x

- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.x
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
cache: "npm"
cache-dependency-path: |
apps/mobile/package-lock.json
apps/web/package-lock.json
packages/core/package-lock.json
packages/crypto/package-lock.json
packages/crypto-worker/package-lock.json
packages/editor-mobile/package-lock.json
packages/editor/package-lock.json
packages/logger/package-lock.json
packages/streamable-fs/package-lock.json
packages/theme/package-lock.json
- name: Prepare environment
run: |
npm ci
npm ci --no-audit
- name: Add environment variables
run: |
echo "EMAIL=${{ secrets.USER_EMAIL }}" >> $GITHUB_ENV
echo "PASSWORD='${{ secrets.USER_PASSWORD }}'" >> $GITHUB_ENV
echo "HASHED_PASSWORD=${{ secrets.USER_HASHED_PASSWORD }}" >> $GITHUB_ENV
echo "NX_CLOUD_ACCESS_TOKEN=${{ secrets.NX_CLOUD_ACCESS_TOKEN }}" >> $GITHUB_ENV
- name: Run all @notesnook/core tests
run: npx nx test:e2e @notesnook/core
95 changes: 77 additions & 18 deletions .github/workflows/web.tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
paths:
- "apps/web/**"
# re-run workflow if workflow file changes
- ".github/workflows/web.tests.yml"
- ".github/workflows/web.tests.yml"
pull_request:
types:
- "ready_for_review"
Expand All @@ -17,15 +17,69 @@ on:
- "reopened"

jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.x
cache: "npm"
cache-dependency-path: |
apps/mobile/package-lock.json
apps/web/package-lock.json
packages/core/package-lock.json
packages/crypto/package-lock.json
packages/crypto-worker/package-lock.json
packages/editor-mobile/package-lock.json
packages/editor/package-lock.json
packages/logger/package-lock.json
packages/streamable-fs/package-lock.json
packages/theme/package-lock.json
- name: Install packages
run: |
npm i --ignore-scripts --no-audit
npx lerna bootstrap --ignore=@notesnook/mobile -- --no-audit
- name: Setup environment
run: |
echo "NX_CLOUD_ACCESS_TOKEN=${{ secrets.NX_CLOUD_ACCESS_TOKEN }}" >> $GITHUB_ENV
- name: Generate test build
run: npm run build:test:web

- name: Archive build artifact
uses: actions/upload-artifact@v2
with:
name: build
path: apps/web/build/**/*
test:
needs: build
name: 🧪 Test (${{ matrix.shard }}/${{ strategy.job-total }})
strategy:
matrix:
shard: [1, 2, 3]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Use Node.js 16.x
- name: Checkout
uses: actions/checkout@v3

- name: Download build
uses: actions/download-artifact@v3
with:
name: build
path: ./apps/web/build

- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.x
cache: 'npm'
cache: "npm"
cache-dependency-path: |
apps/mobile/package-lock.json
apps/web/package-lock.json
Expand All @@ -37,28 +91,33 @@ jobs:
packages/logger/package-lock.json
packages/streamable-fs/package-lock.json
packages/theme/package-lock.json
- name: Add environment variables
- name: Install packages
run: |
echo "USER_EMAIL=${{ secrets.USER_EMAIL }}" >> $GITHUB_ENV
echo "CURRENT_USER_PASSWORD=${{ secrets.USER_PASSWORD }}" >> $GITHUB_ENV
echo "CURRENT_USER_KEY=${{ secrets.USER_KEY }}" >> $GITHUB_ENV
npm i --ignore-scripts --no-audit
npm install -D @playwright/test
- name: Prepare environment
run: npm ci
- name: Validate build extraction
run: ls -ld ./apps/web/build/index.html

- name: Install Playwright Browsers
run: npx playwright install --with-deps
working-directory: ./apps/web
run: npx playwright install chromium --with-deps
working-directory: apps/web

- name: Generate test build
run: npm run build:test:web
- name: Add environment variables
run: |
echo "USER_EMAIL=${{ secrets.USER_EMAIL }}" >> $GITHUB_ENV
echo "CURRENT_USER_PASSWORD=${{ secrets.USER_PASSWORD }}" >> $GITHUB_ENV
echo "CURRENT_USER_KEY=${{ secrets.USER_KEY }}" >> $GITHUB_ENV
- name: Run all @notesnook/web tests
run: npm run test:web
- name: Run tests
run: npx playwright test --shard=${{ matrix.shard }}/${{ strategy.job-total }}
working-directory: apps/web

- uses: actions/upload-artifact@v3
- name: Upload test results
uses: actions/upload-artifact@v3
if: failure()
with:
name: test-results
name: test-results-${{ matrix.shard }}
path: apps/web/test-results
retention-days: 5
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ build
coverage
node_modules
dist
.DS_STORE
.DS_STORE
nx-cloud.env
5 changes: 1 addition & 4 deletions apps/web/__e2e__/editor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,7 @@ test("select all & backspace should clear all content in editor", async ({
const notes = await app.goToNotes();
const note = await notes.createNote(NOTE);

await notes.editor.editAndWait(async () => {
await notes.editor.selectAll();
await page.keyboard.press("Backspace");
});
await notes.editor.clear();

await notes.newNote();
await note?.openNote();
Expand Down
16 changes: 12 additions & 4 deletions apps/web/__e2e__/keyboard-list-navigation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@ test("pressing Shift+ArrowUp should select previous note", async ({ page }) => {

test("use Shift+ArrowUp & Shift+ArrowDown for note selection", async ({
page
}) => {
}, info) => {
info.setTimeout(60 * 1000);

const { notesList, notes } = await populateList(page, 10);
await notes.focus();
// move focus 5 items down
Expand Down Expand Up @@ -187,7 +189,9 @@ test("use Shift+ArrowUp & Shift+ArrowDown for note selection", async ({
expect(await notesList[5].isSelected()).toBeTruthy();
});

test("select notes using Control+Click", async ({ page }) => {
test("select notes using Control+Click", async ({ page }, info) => {
info.setTimeout(60 * 1000);

const { notesList, notes } = await populateList(page, 10);
await notes.focus();

Expand All @@ -202,7 +206,9 @@ test("select notes using Control+Click", async ({ page }) => {
}
});

test("select notes using Shift+Click downwards", async ({ page }) => {
test("select notes using Shift+Click downwards", async ({ page }, info) => {
info.setTimeout(60 * 1000);

const { notesList, notes } = await populateList(page, 10);
await notes.focus();

Expand All @@ -216,7 +222,9 @@ test("select notes using Shift+Click downwards", async ({ page }) => {
expect(await notesList[6].isSelected()).toBeFalsy();
});

test("select notes using Shift+Click upwards", async ({ page }) => {
test("select notes using Shift+Click upwards", async ({ page }, info) => {
info.setTimeout(60 * 1000);

const { notesList, notes } = await populateList(page, 10);
await notes.focus();

Expand Down
10 changes: 8 additions & 2 deletions apps/web/__e2e__/models/editor.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,13 @@ export class EditorModel {
});
}

async clear() {
await this.editAndWait(async () => {
await this.selectAll();
await this.content.press("Backspace");
});
}

async editAndWait(action: () => Promise<void>) {
const oldDateEdited = await this.getDateEdited();
await action();
Expand Down Expand Up @@ -154,8 +161,7 @@ export class EditorModel {

async selectAll() {
await this.content.focus();
await this.page.keyboard.press("Home");
await this.page.keyboard.press("Shift+End");
await this.page.keyboard.press("Control+a");
await this.page.waitForTimeout(500);
}

Expand Down
13 changes: 5 additions & 8 deletions apps/web/__e2e__/sync.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const NOTE = {
test("edits in a note opened on 2 devices should sync in real-time", async ({
browser
}, info) => {
info.setTimeout(30 * 1000);
info.setTimeout(60 * 1000);
const newContent = makeid(24).repeat(2);

const [deviceA, deviceB] = await Promise.all([
Expand All @@ -68,19 +68,16 @@ test("edits in a note opened on 2 devices should sync in real-time", async ({
const noteA = await notesA.findNote(NOTE);
await Promise.all([noteA, noteB].map((note) => note?.openNote()));

const [beforeContentA, beforeContentB] = await Promise.all(
[notesA, notesB].map((notes) => notes?.editor.getContent("text"))
);
await notesB.editor.clear();
await actAndSync([deviceA, deviceB], notesB.editor.setContent(newContent));

const [afterContentA, afterContentB] = await Promise.all(
[notesA, notesB].map((notes) => notes?.editor.getContent("text"))
);

expect(noteA).toBeDefined();
expect(noteB).toBeDefined();
expect(beforeContentA).toBe(beforeContentB);
expect(afterContentA).toBe(`${newContent}${beforeContentA}`);
expect(afterContentB).toBe(`${newContent}${beforeContentB}`);
expect(afterContentA).toBe(newContent);
expect(afterContentB).toBe(newContent);
});

function makeid(length: number) {
Expand Down
24 changes: 15 additions & 9 deletions apps/web/package-lock.json

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

14 changes: 2 additions & 12 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"zustand": "^3.3.1"
},
"devDependencies": {
"@playwright/test": "^1.24.1",
"@playwright/test": "^1.26.0",
"@types/file-saver": "^2.0.5",
"@types/hookrouter": "^2.2.5",
"@types/node-fetch": "^2.5.10",
Expand Down Expand Up @@ -99,14 +99,13 @@
"start:desktop": "env-cmd -e all,desktop react-scripts start",
"start:test": "serve -s build/ -p 3000",
"build": "env-cmd -e all,web react-scripts --max_old_space_size=8092 build",
"build:test": "env-cmd -e all,dev,web,silent react-scripts build",
"build:test": "env-cmd -e all,dev,web,silent react-scripts build --test",
"build:beta": "env-cmd -e all,web,beta react-scripts build",
"build:profile": "env-cmd -e all,web react-scripts build --profile",
"build:desktop": "env-cmd -e all,desktop react-scripts build",
"deploy": "./scripts/deploy.sh",
"debug": "env-cmd -e all,dev,web,silent react-scripts start",
"test": "playwright test",
"test:all": "env-cmd -e test playwright test",
"eject": "react-scripts eject",
"analyze": "source-map-explorer 'build/static/js/*.js'",
"postinstall": "patch-package"
Expand All @@ -133,14 +132,5 @@
},
"volta": {
"node": "16.15.1"
},
"nx": {
"targets": {
"build": {
"outputs": [
"{projectRoot}/build"
]
}
}
}
}
Loading

0 comments on commit 6d75476

Please sign in to comment.