Skip to content

Commit

Permalink
Merge pull request #378 from ReadAlongs/dev.del/feat-editor-e2e
Browse files Browse the repository at this point in the history
feat: extended studio-web end-to-end test suite to include tests for editor interface
  • Loading branch information
deltork authored Jan 9, 2025
2 parents 2e5216a + 1813969 commit 44b9915
Show file tree
Hide file tree
Showing 14 changed files with 592 additions and 32 deletions.
33 changes: 17 additions & 16 deletions .github/workflows/end-to-end-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ on:
- push
- workflow_call
jobs:
test-suites:
web-component-suites:
name: Web-Component tests and utilities verification
runs-on: ubuntu-latest
# Stop the occasional rogue instance before the 6h GitHub limit
timeout-minutes: 15
Expand All @@ -22,10 +23,6 @@ jobs:
- name: Install everything
run: npm install

- name: Ng test for studio-web
run: |
npx nx build web-component
npx nx test:once studio-web
- name: Cypress run for web-component
uses: cypress-io/github-action@v6
with:
Expand Down Expand Up @@ -54,15 +51,15 @@ jobs:
npx nx bundle web-component
git status
git diff --word-diff=porcelain --word-diff-regex=... --color | perl -ple 's/^(\x1b[^ -+]{0,6})? (.{81,})$/$1 . " " . substr($2, 0, 40) . " [... " . (length($2)-80) . " bytes ...] " . substr($2, -40)/ex'
playwright-tests:
name: Run Playwright test-suites
studio-e2e-tests:
name: Studio Web test-suites
timeout-minutes: 60
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
shardIndex: [1, 2, 3]
shardTotal: [3]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
Expand All @@ -72,22 +69,26 @@ jobs:
run: |
git clone https://github.com/ReadAlongs/Studio
cd Studio
pip install -e . -r requirements.api.txt
pip install -e .[api]
./run-web-api.sh &
# wait for the API to be up
curl --retry 20 --retry-delay 1 --retry-all-errors http://localhost:8000/api/v1/langs
- name: Install everything
run: npm install
- name: Install dependencies
run: npm ci
- name: Ng test for studio-web
run: |
npx nx build web-component
npx nx test:once studio-web
- name: Run studio-web in the background
run: |
npx nx build web-component
npx nx run-many --targets=serve,serve-fr,serve-es --projects=web-component,studio-web --parallel 6 &
# wait for the studio web to be up
sleep 100
curl --retry 20 --retry-delay 30 --retry-all-errors http://localhost:4200
sleep 50
curl --retry 20 --retry-delay 10 --retry-all-errors http://localhost:4200 > /dev/null
- name: Run Playwright tests for studio-web
run: |
npx playwright install --with-deps chromium
Expand All @@ -102,8 +103,8 @@ jobs:
merge-reports:
# Merge reports after playwright-tests, even if some shards have failed
if: ${{ !cancelled() }}
needs: [playwright-tests]
name: "Merge playwright reports"
needs: [studio-e2e-tests]
name: "Merge playwright reports from studio-web end-to-end tests"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -123,10 +124,10 @@ jobs:
pattern: blob-report-*
merge-multiple: true

- name: Merge into HTML Report
- name: Merge into a single HTML Report
run: npx playwright merge-reports --reporter=html,github ./all-blob-reports

- name: Upload HTML report
- name: Upload single HTML report
uses: actions/upload-artifact@v4
with:
name: html-report--attempt-${{ github.run_attempt }}
Expand Down
33 changes: 30 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,18 @@ This mono repo, formerly called Web-Component, now called Studio-Web, combines f
- [Studio-Web](#studio-web)
- [Understanding where the components come from when you run locally](#understanding-where-the-components-come-from-when-you-run-locally)
- [Testing](#testing)
- [TL;DR](#tldr)
- [Web-Component](#web-component-1)
- [Studio-Web](#studio-web-1)
- [End-to-End tests](#end-to-end-tests)
- [Internationalization (i18n) and localization (l10n)](#internationalization-i18n-and-localization-l10n)
- [Build \& Publish](#build--publish-the-web-component)
- [Build \& Publish the Web Component](#build--publish-the-web-component)
- [Preparing to publish the Web Component \& Angular Wrapper](#preparing-to-publish-the-web-component--angular-wrapper)
- [Web Component \& Angular Wrapper - via a tag push](#web-component--angular-wrapper---via-a-tag-push)
- [Web Component \& Angular Wrapper - manually - please don't do this!](#web-component--angular-wrapper---manually---please-dont-do-this)
- [Build \& Deploy the Studio-Web App](#build--deploy-the-studio-web-app)
- [Build \& Deploy the Studio-Web app](#build--deploy-the-studio-web-app)
- [Automated Deployment](#automated-deployment)
- [Build Studio-Web and deploy it somewhere else](#build-studio-web-and-deploy-it-somewhere-else)
- [Maintainers](#maintainers)
- [Contributing](#contributing)
- [Acknowledgements](#acknowledgements)
Expand Down Expand Up @@ -189,6 +193,10 @@ to serve or import. In the instructions above, we actually show two methods you
npm install
npx nx run-many --targets=serve-test-data,serve,test:once --projects=web-component
# Ctrl-C once "✔ All specs passed! 01:01 34 34" appears (34 specs as of writing)
npx playwright install --with-deps firefox chromium webkit
npx nx run-many --targets=serve-test-data,serve-web-api,serve,serve-fr,serve-es --projects=web-component,studio-web --parallel 6
npx nx e2e studio-web
#Expect "47 passed (4.6m)" (47 tests as of writing)
npx nx test:once studio-web
# Expect "TOTAL: 25 SUCCESS" (25 tests as of writing)
npx nx extract-i18n studio-web
Expand Down Expand Up @@ -224,10 +232,29 @@ Alternatively run together as:
#### Studio-Web

To run the unit tests for Studio-Web, first build `web-component` in one of the ways listed
above (or just `npx nx build web-component`) if you have not already done so, and then run:
above (or just `npx nx build web-component`) if you have not already done so, and then
run:

npx nx test:once studio-web

##### End-to-End tests

To run the end-to-end tests for Studio-Web, please check the following:

- Ensure that you have built the `web-component` (run `npx nx build web-component`)
- Check that `studio-cli` is installed and running (run `npx nx serve-web-api studio-web`)
- Confirm that `studio-web` is up and running (run `npx nx run-many --targets=serve,serve-fr,serve-es --projects=studio-web --parallel 3`). Your browser must be able to load `http://localhost:4200/` before you proceed.
- Verify that `playwright` is installed and configured (run `npx playwright install --with-deps firefox chromium webkit`)

Alternatively run together as:

npx playwright install --with-deps firefox chromium webkit && npx nx run-many --targets=serve-test-data,serve-web-api,serve,serve-fr,serve-es --projects=web-component,studio-web --parallel 6

Once you have confirmed that everything is online and working run:
`npx nx e2e studio-web` and wait for the report.

**PS**: If you want to run a spec interactively you can run `npx nx e2e-ui studio-web` to get playwright interactive user interface.

### Internationalization (i18n) and localization (l10n)

`studio-web` is localized in French and Spanish. When you add new strings that need localizing,
Expand Down
2 changes: 1 addition & 1 deletion packages/studio-web/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default defineConfig({
/* Retry on CI only */
retries: process.env.CI ? 2 : 3,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : 2,
workers: process.env.CI ? 4 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: process.env.CI ? [["blob", { open: "never" }]] : "html",
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
Expand Down
7 changes: 6 additions & 1 deletion packages/studio-web/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
ReadAlong Studio
</span>
<span class="nav-spacer"></span>
<button class="d-md-none" mat-button [matMenuTriggerFor]="menu">
<button
class="d-md-none"
data-test-id="menu-toggle"
mat-button
[matMenuTriggerFor]="menu"
>
<mat-icon>menu</mat-icon>
</button>
<mat-menu #menu="matMenu">
Expand Down
12 changes: 8 additions & 4 deletions packages/studio-web/src/app/shared/download/download.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,14 @@ Please host all assets on your server, include the font and package imports defi
}

registerDownloadEvent(selectedOutputFormat: SupportedOutputs, from: string) {
const win = window;
(win as any).plausible(`Download`, {
props: { fileType: selectedOutputFormat, downloadSource: from },
});
try {
const win = window;
(win as any).plausible(`Download`, {
props: { fileType: selectedOutputFormat, downloadSource: from },
});
} catch (err) {
console.error(err);
}
}

async createSingleFileBlob(
Expand Down
95 changes: 95 additions & 0 deletions packages/studio-web/tests/editor/check-page.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { test, expect } from "@playwright/test";
import { testAssetsPath, disablePlausible } from "../test-commands";
test.describe.configure({ mode: "parallel" });
test("should check editor UI", async ({ page, isMobile }) => {
await page.goto("/", { waitUntil: "load" });

await disablePlausible(page);
if (isMobile) {
await page.getByTestId("menu-toggle").click();
}
await page.getByRole("button", { name: /Editor/ }).click();
await expect(
page.getByRole("button", { name: "Take the tour!" }),
"Tour button is visible",
).toBeVisible();
await expect(
page.locator("#updateRAS"),
"Choose file is visible",
).toBeVisible();
let fileChooserPromise = page.waitForEvent("filechooser");
await page.locator("#updateRAS").click();
let fileChooser = await fileChooserPromise;
fileChooser.setFiles(testAssetsPath + "sentence-paragr.html");
//check audio bar
/**
* We are using css classes instead of test-id because this is an external plugin
* failure here means the plugin version has changed we should test impact on our app
*/

await expect(
page.locator("#audioToolbar"),
"audio bar should exist",
).toHaveCount(1);
await expect(
page.locator("segment.wavesurfer-segment"),
"should seven audio segments",
).toHaveCount(7);
await expect(
page.locator("segment.wavesurfer-segment:first-of-type > .segment-content"),
"audio segments text should be editable",
).toHaveAttribute("contenteditable", "true");
await expect(
page.locator(
"segment.wavesurfer-segment:first-of-type > .wavesurfer-handle",
),
"audio segments boundaries should exist",
).toHaveCount(2);

//check readalong
await expect(
page.locator("#readalongContainer"),
"should check that readalong is loading",
).not.toBeEmpty();
const header = page.locator(
"#readalongContainer span[slot=read-along-header]",
);
await expect(header, "should have correct title").toContainText(
"Sentence Paragraph Page",
);
await expect(header, "should have editable title").toHaveAttribute(
"contenteditable",
"true",
);
const subheader = page.locator(
"#readalongContainer span[slot=read-along-subheader]",
);
await expect(subheader, "should have correct subtitle").toContainText(
"by me",
);
await expect(subheader, "should have editable subtitle").toHaveAttribute(
"contenteditable",
"true",
);
await page.locator("#t0b0d0p1s0").scrollIntoViewIfNeeded();
await expect(
page.locator("#t0b0d0p0s0").getByLabel("Remove translation"),
"should have translation for first paragraph first sentence",
).toBeVisible();
await expect(
page.locator("#t0b0d0p0s1").getByRole("button", { name: "add" }),
"should not have translation for first paragraph second sentence",
).toBeVisible();
await expect(
page.locator("#t0b0d0p1s0").getByLabel("Remove translation"),
"should have translation for second paragraph ",
).toBeVisible();
await expect(
page.locator("#fileElem--t0b0d0"),
"should not have image on first page",
).toHaveCount(1);
await expect(
page.locator("#t0b0d1 img"),
"should have image on second page",
).toHaveCount(1);
});
40 changes: 40 additions & 0 deletions packages/studio-web/tests/editor/edit-images.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { test, expect } from "@playwright/test";
import { testAssetsPath, editorDefaultBeforeEach } from "../test-commands";
test.describe.configure({ mode: "parallel" });

test("should edit images (editor)", async ({ page, isMobile }) => {
await expect(async () => {
await editorDefaultBeforeEach(page, isMobile);
}).toPass();
await page.locator("#updateRAS").waitFor({ state: "visible" });
await expect(
page.locator("#fileElem--t0b0d0"),
"should not have image on first page",
).toHaveCount(1);
//upload a photo to page 1
let fileChooserPromise = page.waitForEvent("filechooser");
page.locator("#fileElem--t0b0d0").dispatchEvent("click");

let fileChooser = await fileChooserPromise;
fileChooser.setFiles(testAssetsPath + "page1.png");
await expect(
page.locator("#t0b0d0 img"),
"should have image on first page",
).toHaveCount(1);
//delete photo page 2 and re-add
const progressBar = page.getByTestId("progress-bar");
const progressBarBoundingBox = await progressBar.boundingBox();

await progressBar.click({
force: true,
position: {
x: progressBarBoundingBox?.x || 0,
y: progressBarBoundingBox ? progressBarBoundingBox.width * 0.9 : 0,
},
});
await page.locator("#t0b0d1").getByTestId("delete-button").click();
await expect(
page.locator("#fileElem--t0b0d1"),
"should remove image on second page",
).toHaveCount(1);
});
45 changes: 45 additions & 0 deletions packages/studio-web/tests/editor/edit-translations.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { test, expect } from "@playwright/test";
import { editorDefaultBeforeEach } from "../test-commands";
test.describe.configure({ mode: "parallel" });

test("should edit translations (editor)", async ({ page, isMobile }) => {
await expect(async () => {
await editorDefaultBeforeEach(page, isMobile);
}).toPass();
await page.locator("#t0b0d0p0s0translation").waitFor({ state: "visible" });
//edit first sentence translation
await page.locator("#t0b0d0p0s0translation").fill("Un vrai test.");
await expect(page.locator("#t0b0d0p0s0translation")).toContainText(
"Un vrai test.",
);
//add translation to second sentence
await page
.locator("#t0b0d0p0s1")
.getByTestId("add-translation-button")
.click();
await page.locator("#t0b0d0p0s1translation").fill("Phrase.");
//remove third sentence
await page
.locator("#t0b0d0p1s0")
.getByTestId("remove-translation-button")
.click();
await page
.locator("#t0b0d0p1s0")
.getByTestId("add-translation-button")
.waitFor({ state: "visible" });
//toggle translations
await page.getByTestId("translation-toggle").click();
await expect(
page.locator(".sentence__translation.invisible"),
" translations should be hidden",
).not.toHaveCount(0);
await page.getByTestId("translation-toggle").click();
await expect(
page.locator(".sentence__translation.invisible"),
" translations should not be hidden",
).toHaveCount(0);
await expect(
page.getByTestId("translation-line"),
" translations should not be hidden",
).toHaveCount(2);
});
Loading

0 comments on commit 44b9915

Please sign in to comment.