Skip to content

Commit

Permalink
Merge pull request #5204 from Gustry/pom-project-page-playwright
Browse files Browse the repository at this point in the history
Tests - Start Page Object Model for Playwright
  • Loading branch information
Gustry authored Jan 16, 2025
2 parents 7f92206 + e92bf17 commit 62f19fe
Show file tree
Hide file tree
Showing 6 changed files with 215 additions and 62 deletions.
23 changes: 12 additions & 11 deletions tests/end2end/playwright/attribute-table.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @ts-check
import { test, expect } from '@playwright/test';
import { ProjectPage } from './pages/project';
import { gotoMap } from './globals';

test.describe('Attribute table', () => {
Expand All @@ -9,18 +10,17 @@ test.describe('Attribute table', () => {
});

test('Thumbnail class generate img with good path', async ({ page }) => {
await page.locator('a#button-attributeLayers').click();
// display form
//await page.locator('#button-edition').click();
await page.locator('#attribute-layer-list-table').locator('button[value=Les_quartiers_a_Montpellier]').click();
await expect(page.locator('#attribute-layer-table-Les_quartiers_a_Montpellier tbody tr')).toHaveCount(7);
const project = new ProjectPage(page, 'attribute_table');
const layerName = 'Les_quartiers_a_Montpellier';

await project.openAttributeTable(layerName);
await expect(project.attributeTableHtml(layerName).locator('tbody tr')).toHaveCount(7);
// mediaFile as stored in data-src attributes
const mediaFile = await page.locator('#attribute-layer-table-Les_quartiers_a_Montpellier img.data-attr-thumbnail').first().getAttribute('data-src');
const mediaFile = await project.attributeTableHtml(layerName).locator('img.data-attr-thumbnail').first().getAttribute('data-src');
// ensure src contain "dynamic" mediaFile
await expect(page.locator('#attribute-layer-table-Les_quartiers_a_Montpellier img.data-attr-thumbnail').first()).toHaveAttribute('src', new RegExp(mediaFile));
await expect(project.attributeTableHtml(layerName).locator('img.data-attr-thumbnail').first()).toHaveAttribute('src', new RegExp(mediaFile));
// ensure src contain getMedia and projet URL
await expect(page.locator('#attribute-layer-table-Les_quartiers_a_Montpellier img.data-attr-thumbnail').first()).toHaveAttribute('src', /getMedia\?repository=testsrepository&project=attribute_table&/);
await expect(project.attributeTableHtml(layerName).locator('img.data-attr-thumbnail').first()).toHaveAttribute('src', /getMedia\?repository=testsrepository&project=attribute_table&/);
});
});

Expand All @@ -37,8 +37,9 @@ test.describe('Attribute table data restricted to map extent', () => {
});

test('Data restriction, refresh button behaviour and export', async ({ page }) => {
await page.locator('a#button-attributeLayers').click();
await page.locator('#attribute-layer-list-table').locator('button[value=Les_quartiers_a_Montpellier]').click();
const project = new ProjectPage(page, 'attribute_table');
const layerName = 'Les_quartiers_a_Montpellier';
await project.openAttributeTable(layerName);

await expect(page.locator('.btn-refresh-table')).not.toHaveClass(/btn-warning/);

Expand All @@ -53,7 +54,7 @@ test.describe('Attribute table data restricted to map extent', () => {
// Refresh
await page.locator('.btn-refresh-table').click();

await expect(page.locator('#attribute-layer-table-Les_quartiers_a_Montpellier tbody tr')).toHaveCount(5);
await expect(project.attributeTableHtml(layerName).locator('tbody tr')).toHaveCount(5);

const getFeatureRequestPromise = page.waitForRequest(request => request.method() === 'POST' && request.postData() != null && request.postData()?.includes('GetFeature') === true);
// bbox in getFeature request for export
Expand Down
34 changes: 13 additions & 21 deletions tests/end2end/playwright/edition-form.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @ts-check
import { test, expect } from '@playwright/test';
import { gotoMap } from './globals';
import {ProjectPage} from "./pages/project";

test.describe('Edition Form Validation', () => {

Expand All @@ -10,9 +11,8 @@ test.describe('Edition Form Validation', () => {
});

test('Input type number with range and step', async ({ page }) => {
// display form
await page.locator('#button-edition').click();
await page.locator('a#edition-draw').click();
const project = new ProjectPage(page, 'form_edition_all_field_type');
await project.openEditingFormWithLayer('form_edition_all_fields_types');

// ensure input attributes match with field config defined in project
await expect(page.locator('#jforms_view_edition input[name="integer_field"]')).toHaveAttribute('type', 'number')
Expand All @@ -24,22 +24,17 @@ test.describe('Edition Form Validation', () => {
await page.locator('#jforms_view_edition input[name="integer_field"]').fill('50');

// submit form
await page.locator('#jforms_view_edition__submit_submit').click();
// will close & show message
await expect(page.locator('#edition-form-container')).toBeHidden();
await expect(page.locator('#lizmap-edition-message')).toBeVisible();
await project.editingSubmitForm()
})

test('Boolean nullable w/ value map', async ({ page }) => {

let editFeatureRequestPromise = page.waitForResponse(response => response.url().includes('editFeature'));

await page.locator('#button-edition').click();
await page.locator('#edition-layer').selectOption({ label: 'many_bool_formats' });
await page.locator('#edition-draw').click();
await page.locator('#jforms_view_edition_liz_future_action').selectOption('edit');
const project = new ProjectPage(page, 'form_edition_all_field_type');
await project.openEditingFormWithLayer('many_bool_formats');
await page.getByLabel('bool_simple_null_vm').selectOption('t');
await page.locator('#jforms_view_edition__submit_submit').click();
await project.editingSubmitForm('edit');

await editFeatureRequestPromise;

Expand All @@ -49,7 +44,7 @@ test.describe('Edition Form Validation', () => {
await expect(page.getByLabel('bool_simple_null_vm')).toHaveValue('t');

await page.getByLabel('bool_simple_null_vm').selectOption('');
await page.locator('#jforms_view_edition__submit_submit').click();
await project.editingSubmitForm('edit');

await editFeatureRequestPromise;

Expand All @@ -68,8 +63,8 @@ test.describe('Edition Form Validation', () => {
});
});

// display form
await page.locator('#button-edition').click();
const project = new ProjectPage(page, 'form_edition_all_field_type');
await project.buttonEditing.click();
await page.locator('a#edition-draw').click();

// message
Expand Down Expand Up @@ -522,12 +517,9 @@ test.describe('Text widget in a form', () => {

let getFeatureInfoRequestPromise = page.waitForRequest(request => request.method() === 'POST' && request.postData()?.includes('GetFeatureInfo') === true);

await page.locator('#newOlMap').click({
position: {
x: 354,
y: 370
}
});
const project = new ProjectPage(page, 'text_widget');

await project.clickOnMap(354, 370);

await getFeatureInfoRequestPromise;

Expand Down
10 changes: 4 additions & 6 deletions tests/end2end/playwright/media.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @ts-check
import { test, expect } from '@playwright/test';
import { gotoMap } from './globals';
import {ProjectPage} from "./pages/project";

test.describe('Media', () => {
test('Tests media are deleted', async ({ page }) => {
Expand All @@ -17,14 +18,11 @@ test.describe('Media', () => {
await expect(response).toBeOK();

// Open the attribute table
const url = '/index.php/view/map?repository=testsrepository&project=form_edition_all_field_type';
await gotoMap(url, page);

await page.locator('#button-attributeLayers').click();

const project = new ProjectPage(page, 'form_edition_all_field_type');
await project.open();
let getFeatureRequestPromise = page.waitForRequest(request => request.method() === 'POST' && request.postData()?.includes('GetFeature') === true);

await page.locator('#attribute-layer-list button[value="form_edition_upload"]').click();
await project.openAttributeTable('form_edition_upload');
await getFeatureRequestPromise;

await page.getByRole('row', { name: '2 text_file_mandatory' }).getByRole('button').nth(2);
Expand Down
163 changes: 163 additions & 0 deletions tests/end2end/playwright/pages/project.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// @ts-check
import {expect, Locator, Page} from '@playwright/test';
import { gotoMap } from '../globals';

export class ProjectPage {
/** @type {Page} */
page;

// Metadata
/**
* Project name metadata
* @type {string}
*/
project;
/**
* Repository name metadata
* @type {string}
*/
repository;

// Menu
/**
* Layer switcher menu
* @type {Locator}
*/
switcher;
/**
* Editing menu
* @type {Locator}
*/
buttonEditing;

// Docks
/**
* Attribute table dock
* @type {Locator}
*/
attributeTable;
/**
* Main left dock
* @type {Locator}
*/
dock;
/**
* Right dock
* @type {Locator}
*/
rightDock;
/**
* Bottom dock
* @type {Locator}
*/
bottomDock;
/**
* Mini dock
* @type {Locator}
*/
miniDock;
/**
* Top search bar
* @type {Locator}
*/
search;

// Messages
/**
* Foreground message bar
* @type {Locator}
*/
warningMessage;

/**
* Attribute table for the given layer name
* @param {string} name Name of the layer
* @returns {Locator}
*/
attributeTableHtml = (name) =>
this.page.locator(`#attribute-layer-table-${name}`);

/**
* Constructor
* @param {Page} page The playwright page
* @param {string} project The project name
* @param {string} repository The repository name, default to testsrepository
*/
constructor(page, project, repository = 'testsrepository') {
this.page = page;
this.project = project;
this.repository = repository;
this.dock = page.locator('#dock');
this.rightDock = page.locator('#right-dock');
this.bottomDock = page.locator('#bottom-dock');
this.miniDock = page.locator('#mini-dock-content');
this.warningMessage = page.locator('#lizmap-warning-message');
this.search = page.locator('#search-query');
this.switcher = page.locator('#button-switcher');
this.buttonEditing = page.locator('#button-edition');
}

/**
* open function
* Open the URL for the given project and repository
*/
async open(){
await gotoMap(`/index.php/view/map?repository=${this.repository}&project=${this.project}`, this.page);
}

/**
* openAttributeTable function
* Open the attribute table for the given layer
* @param {string} layer Name of the layer
* @param {boolean} maximise If the attribute table must be maximised
*/
async openAttributeTable(layer, maximise = false){
await this.page.locator('a#button-attributeLayers').click();
if (maximise) {
await this.page.getByRole('button', { name: 'Maximize' }).click();
}
await this.page.locator('#attribute-layer-list-table').locator(`button[value=${layer}]`).click();
}

/**
* editingSubmitForm function
* Submit the form
* @param {string} futureAction The action to do after submit : can be close/create/edit.
*/
async editingSubmitForm(futureAction = 'close'){
await this.page.locator('#jforms_view_edition_liz_future_action').selectOption(futureAction);
await this.page.locator('#jforms_view_edition__submit_submit').click();
if (futureAction === 'close'){
await expect(this.page.locator('#edition-form-container')).toBeHidden();
} else {
await expect(this.page.locator('#edition-form-container')).toBeVisible();
}
await expect(this.page.locator('#lizmap-edition-message')).toBeVisible();
}

/**
* openEditingFormWithLayer function
* Open the editing panel with the given layer name form
* @param {string} layer Name of the layer
*/
async openEditingFormWithLayer(layer){
await this.buttonEditing.click();
await this.page.locator('#edition-layer').selectOption({ label: layer });
await this.page.locator('a#edition-draw').click();
}

/**
* clickOnMap function
* Click on the map at the given position
* @param {number} x Position X on the map
* @param {number} y Position Y on the map
*/
async clickOnMap(x, y){
await this.page.locator('#newOlMap').click({
position: {
x: x,
y: y
}
});
}
}
16 changes: 7 additions & 9 deletions tests/end2end/playwright/project_load_warning.spec.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
// @ts-check
import { test, expect } from '@playwright/test';
import { gotoMap } from './globals';
import { ProjectPage } from './pages/project';

test.describe('Project warnings in CFG as admin', () => {
test.use({ storageState: 'playwright/.auth/admin.json' });

test('Visit map with a warning', async ({ page }) => {
const url = '/index.php/view/map?repository=testsrepository&project=project_cfg_warnings';
await gotoMap(url, page)

await expect(page.locator("#lizmap-warning-message")).toBeVisible();
const project = new ProjectPage(page, 'project_cfg_warnings');
await project.open();
await expect(project.warningMessage).toBeVisible();
});

});

test.describe('Project warnings in CFG as anonymous', () => {

test('Visit map without a warning', async ({ page }) => {
const url = '/index.php/view/map?repository=testsrepository&project=project_cfg_warnings';
await gotoMap(url, page)

await expect(page.locator("#lizmap-warning-message")).toHaveCount(0);
const project = new ProjectPage(page, 'project_cfg_warnings');
await project.open();
await expect(project.warningMessage).toHaveCount(0);
});

});
Loading

0 comments on commit 62f19fe

Please sign in to comment.