Skip to content

Commit

Permalink
feedback from group review
Browse files Browse the repository at this point in the history
  • Loading branch information
stephenkilbourn committed Mar 1, 2024
1 parent 2f6b1a6 commit f9fa928
Show file tree
Hide file tree
Showing 8 changed files with 178 additions and 33 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Playwright Tests
on:
push:
branches: [ main, master, develop ]
pull_request:
branches: [ main, master, develop ]
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- uses: actions/setup-node@v3
with:
node-version: 16
- name: Install yarn
run: npm install -g yarn
- name: Run Veda setup
run: ./.veda/setup
- name: Install Playwright Browsers
run: yarn playwright install --with-deps
- name: Run Playwright tests
run: yarn test:e2e
- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: /veda/ui/playwright-report/
retention-days: 30
30 changes: 20 additions & 10 deletions e2e/generateTestData.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,37 @@ const fg = require('fast-glob');
const catalogPaths = fg.globSync('**/datasets/*.mdx');
const storyPaths = fg.globSync('**/stories/*.mdx');
const catalogNames = [];
const datasetIds = [];
const storyNames = [];

for (const catalog of catalogPaths) {
const catalogData = matter.read(catalog).data;
catalogNames.push(catalogData['name']);
datasetIds.push(catalogData['id']);
}

for (const story of storyPaths) {
const storyData = matter.read(story).data;
storyNames.push(storyData['name'])
storyNames.push(storyData['name']);
}

const testDataJson = {
"catalogs": catalogNames,
"stories": storyNames
}
catalogs: catalogNames,
datasetIds: datasetIds,
stories: storyNames
};

fs.writeFile(path.join(__dirname, 'playwrightTestData.json'), JSON.stringify(testDataJson), err => {
if (err) {
console.error(err);
} else {
console.info('new test data file generated')
fs.writeFile(
path.join(__dirname, 'playwrightTestData.json'),
JSON.stringify(testDataJson),
(err) => {
if (err) {
// eslint-disable-next-line no-console
console.error(err);
throw err;
} else {
// eslint-disable-next-line no-console
console.info('new test data file generated');
}
}
});
);
12 changes: 8 additions & 4 deletions e2e/pages/analysisPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,26 @@ import { Locator, Page, test } from '@playwright/test';

export default class AnalysisPage {
readonly page: Page;
readonly selectDatasetsMessage: Locator;
readonly mainContent: Locator;
readonly header: Locator;
readonly mapboxCanvas: Locator;
readonly generateAnalysisButton: Locator;
readonly datasetOptions: Locator;
readonly datasetCheckbox: Locator;
readonly moreOptionsButton: Locator;
readonly northAmericaOption: Locator;


constructor(page: Page) {
this.page = page;
this.selectDatasetsMessage = this.page.getByText(/To select datasets, please define an area and a date first/i);
this.mainContent = this.page.getByRole('main');
this.header = this.mainContent.getByRole('heading', {level: 1, name: /analysis/i });
this.mapboxCanvas = this.page.getByLabel('Map', { exact: true });
this.generateAnalysisButton = this.page.getByRole('link', { name: /Generate analysis/i });
this.datasetOptions = this.page.getByTestId('datasetOptions');
this.datasetCheckbox = this.datasetOptions.getByRole('checkbox');
this.datasetCheckbox = this.page.locator('label').filter({ hasText: /From:/i })
this.moreOptionsButton = this.page.getByRole('button', {name: /more options/i });
this.northAmericaOption = this.page.getByRole('button', {name: /north america/i });
}

async drawPolygon (polygonCorners: number[][]) {
Expand Down Expand Up @@ -49,7 +53,7 @@ export default class AnalysisPage {

async clickDatasetOption (index: number) {
test.step(`clicking dataset number ${index}`, async () => {
this.datasetCheckbox.nth(index).locator('..').click();
this.datasetCheckbox.nth(index).click();
})
}
}
2 changes: 1 addition & 1 deletion e2e/pages/analysisResultsPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default class AnalysisResultsPage {

constructor(page: Page) {
this.page = page;
this.analysisCards = this.page.getByTestId('analysisCards');
this.analysisCards = this.page.getByRole('article');
}

}
27 changes: 16 additions & 11 deletions e2e/pages/basePage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,24 @@ import { test as base } from '@playwright/test';
import AboutPage from './aboutPage';
import AnalysisPage from './analysisPage';
import AnalysisResultsPage from './analysisResultsPage';
import HomePage from './homePage';
import FooterComponent from './footerComponent';
import HeaderComponent from './headerComponent';
import CatalogPage from './catalogPage';
import DatasetPage from './datasetPage';
import ExplorePage from './explorePage';
import FooterComponent from './footerComponent';
import HeaderComponent from './headerComponent';
import HomePage from './homePage';
import StoryPage from './storyPage';

export const test = base.extend<{
aboutPage: AboutPage;
analysisPage: AnalysisPage;
analysisResultsPage: AnalysisResultsPage;
catalogPage: CatalogPage;
datasetPage: DatasetPage;
explorePage: ExplorePage;
footerComponent: FooterComponent;
headerComponent: HeaderComponent;
homePage: HomePage;
catalogPage: CatalogPage;
datasetPage: DatasetPage;
storyPage: StoryPage
}> ({
aboutPage: async ({page}, use) => {
Expand All @@ -35,17 +37,20 @@ export const test = base.extend<{
datasetPage: async ({page}, use) => {
await use(new DatasetPage(page));
},
homePage: async ({page}, use) => {
await use(new HomePage(page));
explorePage: async ({page}, use) => {
await use(new ExplorePage(page));
},
storyPage: async ({page}, use) => {
await use(new StoryPage(page));
footerComponent: async ({page}, use) => {
await use(new FooterComponent(page));
},
headerComponent: async ({page}, use) => {
await use(new HeaderComponent(page));
},
footerComponent: async ({page}, use) => {
await use(new FooterComponent(page));
homePage: async ({page}, use) => {
await use(new HomePage(page));
},
storyPage: async ({page}, use) => {
await use(new StoryPage(page));
},
});

Expand Down
11 changes: 11 additions & 0 deletions e2e/pages/explorePage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Locator, Page } from '@playwright/test';

export default class ExplorePage {
readonly page: Page;
readonly layersHeading: Locator;

constructor(page: Page) {
this.page = page;
this.layersHeading = this.page.getByRole('heading', { name: 'Layers' });
}
}
61 changes: 54 additions & 7 deletions e2e/tests/analysis.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { test, expect } from '../pages/basePage';

test('load /analysis route', async ({
test('generate analysis with polygon', async ({
page,
analysisPage,
analysisResultsPage,
}) => {
let pageErrorCalled = false;
// Log all uncaught errors to the terminal
// Log all uncaught errors to the terminal to be visible in trace
page.on('pageerror', exception => {
console.log(`Uncaught exception: "${exception}"`);
console.log(`Uncaught exception: "${JSON.stringify(exception)}"`);
pageErrorCalled = true;
});

Expand All @@ -22,13 +22,58 @@ test('load /analysis route', async ({
const box = await analysisPage.mapboxCanvas.boundingBox();

// using Non-null Assertion because we know the mapbox is visible, therefore box is not null
const firstCorner = [box!.width / 4, box!.height / 4];
const secondCorner = [box!.width / 3, box!.height / 4];
const thirdCorner = [box!.width / 4, box!.height / 3];
const firstCorner = [box!.width * 0.2, box!.height * 0.2];
const secondCorner = [box!.width * 0.8, box!.height * 0.2];
const thirdCorner = [box!.width * 0.8, box!.height * 0.8];
const fourthCorner = [box!.width * 0.2, box!.height * 0.8];


await analysisPage.mapboxCanvas.click();

await analysisPage.drawPolygon([firstCorner, secondCorner, thirdCorner])
await analysisPage.drawPolygon([firstCorner, secondCorner, thirdCorner, fourthCorner])

await expect(analysisPage.selectDatasetsMessage).toBeHidden();
await expect(page.getByText(/loading/i)).toBeHidden();
await analysisPage.clickDatasetOption(1);

const searchResponsePromise = page.waitForResponse(/\/search/i);
await analysisPage.generateAnalysisButton.click();


const searchResponse = await searchResponsePromise;
expect(searchResponse.ok(), 'request to GET /search should be successful').toBeTruthy();

await expect(analysisResultsPage.analysisCards.first(), 'at least one analysis results is visible' ).toBeVisible();

// scroll page to bottom
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));

expect(pageErrorCalled, 'no javascript exceptions thrown on page').toBe(false);

});


test('generate analysis with region select', async ({
page,
analysisPage,
analysisResultsPage,
}) => {
let pageErrorCalled = false;
// Log all uncaught errors to the terminal to be visible in trace
page.on('pageerror', exception => {
console.log(`Uncaught exception: "${JSON.stringify(exception)}"`);
pageErrorCalled = true;
});

const mapboxResponsePromise = page.waitForResponse(/api\.mapbox.com\/v4\/mapbox\.mapbox-streets-v8/i);
await page.goto('/analysis');
await expect(analysisPage.header, `analysis page should load`).toBeVisible();
const mapboxResponse = await mapboxResponsePromise;
expect(mapboxResponse.ok(), 'mapbox request should be successful').toBeTruthy();
await expect(analysisPage.mapboxCanvas, 'mapbox canvas should be visible').toBeVisible();

await analysisPage.moreOptionsButton.click();
await analysisPage.northAmericaOption.click();

await analysisPage.clickDatasetOption(1);

Expand All @@ -41,4 +86,6 @@ test('load /analysis route', async ({

await expect(analysisResultsPage.analysisCards.first(), 'at least one analysis results is visible' ).toBeVisible();

expect(pageErrorCalled, 'no javascript exceptions thrown on page').toBe(false);

});
37 changes: 37 additions & 0 deletions e2e/tests/exploreDatasets.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import fs from 'fs';
import { test, expect } from '../pages/basePage';

const datasetIds = JSON.parse(fs.readFileSync('e2e/playwrightTestData.json', 'utf8')).datasetIds;

test.describe('explore dataset', () => {
for (const dataset of datasetIds) {
test(`${dataset} explore page functions`, async({
page,
explorePage,
}) => {
let pageErrorCalled = false;
// Log all uncaught errors to the terminal to be visible in trace
page.on('pageerror', exception => {
console.log(`Uncaught exception: "${JSON.stringify(exception)}"`);
pageErrorCalled = true;
});

//mosaic isn't hit on all datasets
const collectionsResponsePromise = page.waitForResponse(response =>
response.url().includes('collections') && response.status() === 200
);

await page.goto(`data-catalog/${dataset}/explore`);
await expect(explorePage.layersHeading).toBeVisible();

const mosaicResponse = await collectionsResponsePromise;
expect(mosaicResponse.ok(), 'mapbox request should be successful').toBeTruthy();

// scroll page to bottom
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));

expect(pageErrorCalled, 'no javascript exceptions thrown on page').toBe(false);
});
}

});

0 comments on commit f9fa928

Please sign in to comment.