Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,11 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts

# Playwright
node_modules/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
/playwright/.auth/
66 changes: 64 additions & 2 deletions package-lock.json

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

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"build": "next build",
"start": "next start",
"lint": "next lint",
"preview": "next build && next start"
"preview": "next build && next start",
"test": "playwright test"
},
"dependencies": {
"@emotion/react": "^11.14.0",
Expand Down Expand Up @@ -48,6 +49,7 @@
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@playwright/test": "^1.61.1",
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/pg": "^8.11.11",
Expand Down
84 changes: 84 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
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: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://localhost:3000',
reuseExistingServer: !process.env.CI,
stdout: 'pipe',
stderr: 'pipe',
wait: {
// stdout: /Ready in/
stdout: /Local:\s+(?<test_url>http.+)/
},
},
});
22 changes: 22 additions & 0 deletions tests/fixtures/multipartInterviewPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type {Locator, Page} from '@playwright/test';

export class MultipartInterviewsPage {

readonly helpBox: Locator;
readonly multipartTable: Locator;
readonly resultCount: Locator;
readonly nextPageButton: Locator;
readonly previousPageButton: Locator;

constructor(public readonly page: Page) {
this.helpBox = this.page.getByText('Help differentiate interviews with:1Multi-part Interviews - Interviews that are');
this.resultCount = this.page.getByText(/The following \d+ interviews have multiple parts/);
this.multipartTable = this.page.getByText('ColumnsFiltersDensityExportInterview NameInterview TypeSubject IDStudy IDParts');
this.nextPageButton = this.page.getByRole("button", {description: "Go to next page"});
this.previousPageButton = this.page.getByRole("button", {description: "Go to previous page",});
}

async goto() {
await this.page.goto("/issues/multiPart"); // Assumes baseURL is set correctly in playwright.config.ts
}
}
71 changes: 71 additions & 0 deletions tests/frontPage.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import {expect, test} from '@playwright/test';

test('main components are present', async ({page}) => {
await page.goto("");
await expect(page.getByRole('link', {name: 'AV QC Portal v0.2.0'})).toBeVisible();
await expect(page.getByText('Toggle SidebarHome')).toBeVisible();
await expect(page.getByText('NavigationIssuesToggleMulti-')).toBeVisible();
await expect(page.locator('body')).toMatchAriaSnapshot(`
- list:
- listitem:
- link "AV QC Portal v0.2.0":
- /url: /
- img
- text: ""
`);
});

test.describe("main matter", async () => {

test.beforeEach(async ({page}) => {
await page.goto("");
});

test("Info box", async ({page}) => {
await expect(page.getByRole("main")).toBeVisible();
await expect(page.getByRole("heading", {name: "👋 Welcome to AV QC Portal"})).toBeVisible()
await expect(page.getByText("This web portal is actively being developed as a companion to theAV QC pipelineproject, designed to streamline audiovisual quality control processes.")).toBeVisible();
})
});

test.describe("The sidebar", async () => {

test.beforeEach(async ({page}) => {
await page.goto("");
});

test('Sidebar', async ({page}) => {
await page.goto("");
await expect(page.locator('body')).toMatchAriaSnapshot(`- text: Navigation`);
await expect(page.locator('body')).toMatchAriaSnapshot(`
- list:
- listitem:
- link "Multi-Part Interviews":
- /url: /issues/multiPart
- listitem:
- link "Unlabelled Audio":
- /url: /issues/unlabelledAudio
- listitem:
- link "Missing Interviews":
- /url: /issues/missing
- listitem:
- link "Missing Runsheets":
- /url: /issues/noRunsheet
- listitem:
- link "Missing Transcripts":
- /url: /issues/noTranscript
`);
await expect(page.locator('body')).toMatchAriaSnapshot(`
- link "Interviews":
- /url: /interviews
- img
- text: ""
`);
await expect(page.locator('body')).toMatchAriaSnapshot(`
- link "Audio Journals":
- /url: /journals
- img
- text: ""
`);
})
});
39 changes: 39 additions & 0 deletions tests/issues.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { test, expect } from '@playwright/test';

test('test', async ({ page }) => {
await page.goto("/utils");
await expect(page.getByRole('link', { name: '🔍 Quality Control Monitor' })).toBeVisible();
await page.getByRole('link', { name: '🔍 Quality Control Monitor' }).click();
await expect(page.getByRole('link', { name: '📹 Multi-Part Interviews Mark' })).toBeVisible();
await expect(page.getByRole('link', { name: '🎧 Unlabelled Diarized Audio' })).toBeVisible();
await expect(page.getByRole('link', { name: '📁 Missing Interviews List' })).toBeVisible();
await expect(page.getByRole('link', { name: '📜 Missing Transcripts List' })).toBeVisible();
await expect(page.getByRole('link', { name: '📜 Missing Runsheets List' })).toBeVisible();
await expect(page.getByRole('heading', { name: 'Issues' })).toBeVisible();
await expect(page.getByRole('main')).toContainText('This section covers various issues raised / detected by the AV QC pipeline.');
await expect(page.getByRole('main')).toMatchAriaSnapshot(`
- heading "Issues" [level=2]
- paragraph: This section covers various issues raised / detected by the AV QC pipeline.
- link "📹 Multi-Part Interviews Mark parts of the interview to process, or ignore.":
- /url: /issues/multiPart
- heading "📹 Multi-Part Interviews" [level=4]
- paragraph: Mark parts of the interview to process, or ignore.
- link "🎧 Unlabelled Diarized Audio Label unlabelled audio files with the correct roles, for further downstream processing.":
- /url: /issues/unlabelledAudio
- heading "🎧 Unlabelled Diarized Audio" [level=4]
- paragraph: Label unlabelled audio files with the correct roles, for further downstream processing.
- link "📁 Missing Interviews List interviews with Runsheets marked as conducted, but no data associated with them.":
- /url: /issues/missing
- heading "📁 Missing Interviews" [level=4]
- paragraph: List interviews with Runsheets marked as conducted, but no data associated with them.
- link "📜 Missing Transcripts List interviews with video / audio data, but no associated transcripts.":
- /url: /issues/noTranscript
- heading "📜 Missing Transcripts" [level=4]
- paragraph: List interviews with video / audio data, but no associated transcripts.
- link "📜 Missing Runsheets List interviews with video / audio data, but no associated runsheets.":
- /url: /issues/noRunsheet
- heading "📜 Missing Runsheets" [level=4]
- paragraph: List interviews with video / audio data, but no associated runsheets.
- paragraph: This project is under active development. If you need more issues catalogued, please reach out to developers.
`);
});
39 changes: 39 additions & 0 deletions tests/multiPartInterview.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {expect, test} from './test';

test('can navigate to page', async ({page}) => {
await page.goto("")
await expect(page.getByRole('navigation', {name: 'breadcrumb'})).toBeVisible();
await page.locator('a').filter({hasText: 'Multi-Part Interviews'}).click();
await expect(page.getByRole('heading')).toContainText('Interviews with Multiple Parts');
await expect(page.getByRole('main')).toContainText('Help differentiate interviews with:');
await expect(page.getByRole('main')).toContainText('Multi-part Interviews - Interviews that are split into multiple parts. Common with PSYCHS interviews, where interviews could happen over multiple days.');
await expect(page.getByRole('main')).toContainText('Duplicate Interviews - Interviews that are duplicates of each other. Probably related to Data Flow and renaming files at the source.');
});

test.describe("Multipart Interviews page", async () => {

/**
* Checks all the major static parts of the page are present
*/
test("main components present", async ({page, multipartInterviews}) => {
await expect(multipartInterviews.helpBox).toBeVisible();
await expect(page.getByRole('main')).toContainText('Multi-part Interviews - Interviews that are split into multiple parts. Common with PSYCHS interviews, where interviews could happen over multiple days.');
await expect(page.getByRole('main')).toContainText('Duplicate Interviews - Interviews that are duplicates of each other. Probably related to Data Flow and renaming files at the source.');
await expect(multipartInterviews.multipartTable).toBeVisible();
});

/**
* Checks the results table is well-formed
*/
test('interviews loaded', async ({multipartInterviews}) => {
await expect(multipartInterviews.resultCount).toBeVisible();

// We're on the first page of results so there should be no previous page
await expect(multipartInterviews.previousPageButton).toBeVisible();
await expect(multipartInterviews.previousPageButton).toBeDisabled();

// We're on the next button should be present by may not be enabled
await expect(multipartInterviews.nextPageButton).toBeVisible();
await expect.soft(multipartInterviews.nextPageButton).toBeEnabled();
});
});
Loading