Skip to content

Commit 3260fb6

Browse files
committed
Added UI Tests
1 parent 4e1496d commit 3260fb6

9 files changed

Lines changed: 2924 additions & 0 deletions

File tree

.github/workflows/ui-test.yml

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
name: UI Tests
2+
on:
3+
## Check each PR
4+
push:
5+
pull_request:
6+
## Manual execution on branch
7+
workflow_dispatch:
8+
## Nightly
9+
### Needs secrets
10+
#### GC_PROJECT_ID
11+
#### GC_SERVICE_KEY
12+
#### NIGHTLY_TOKEN
13+
schedule:
14+
- cron: '0 0 * * *'
15+
env:
16+
CAMPAIGN: 'ps_emailalerts'
17+
jobs:
18+
ui_test:
19+
name: UI Tests
20+
runs-on: ubuntu-latest
21+
strategy:
22+
fail-fast: false
23+
matrix:
24+
include:
25+
- PS_VERSION: '1.7.7.8'
26+
PHP_VERSION: '7.3'
27+
- PS_VERSION: '1.7.8.11'
28+
PHP_VERSION: '7.4'
29+
- PS_VERSION: '8.0.5'
30+
PHP_VERSION: '8.1'
31+
- PS_VERSION: '8.1.6'
32+
PHP_VERSION: '8.1'
33+
- PS_VERSION: 'nightly'
34+
PHP_VERSION: '8.2'
35+
env:
36+
PS_VERSION: ${{ matrix.PS_VERSION }}
37+
PHP_VERSION: ${{ matrix.PHP_VERSION }}
38+
steps:
39+
- name: Checkout
40+
uses: actions/checkout@v3.1.0
41+
42+
- name: Setup PHP
43+
uses: shivammathur/setup-php@v2
44+
with:
45+
php-version: ${{ matrix.PHP_VERSION }}
46+
47+
- name: Install dependencies
48+
run: composer install --no-dev && composer dump-autoload -o --no-dev
49+
50+
- name: Start containers
51+
working-directory: tests/UI/
52+
run: |
53+
docker compose -f "docker-compose.yml" up -d --build
54+
bash -c 'while [[ "$(curl -L -s -o /dev/null -w %{http_code} http://localhost/en/)" != "200" ]]; do sleep 5; done'
55+
56+
- name: Install dependencies
57+
working-directory: tests/UI/
58+
run: npm ci
59+
60+
- name: Install Playwright Browsers
61+
working-directory: tests/UI/
62+
run: npx playwright install chromium --with-deps
63+
64+
- name: Run Playwright tests
65+
working-directory: tests/UI/
66+
run: npx playwright test
67+
68+
- name: Export Docker errors
69+
working-directory: tests/UI/
70+
if: always()
71+
run: docker compose logs --no-color >& docker-compose.log
72+
73+
- name: Upload artifact
74+
uses: actions/upload-artifact@v4
75+
if: always()
76+
with:
77+
name: playwright-report-${{ matrix.PS_VERSION }}
78+
path: |
79+
tests/UI/reports/
80+
tests/UI/report.json
81+
tests/UI/docker-compose.log
82+
retention-days: 30
83+
84+
nightly:
85+
name: Nightly Report
86+
if: ${{ github.event_name == 'schedule' }}
87+
needs:
88+
- ui_test
89+
runs-on: ubuntu-latest
90+
strategy:
91+
fail-fast: false
92+
matrix:
93+
PS_VERSION:
94+
- '1.7.7.8'
95+
- '1.7.8.11'
96+
- '8.0.5'
97+
- '8.1.6'
98+
- 'nightly'
99+
permissions:
100+
contents: 'read'
101+
id-token: 'write'
102+
steps:
103+
- name: Checkout
104+
uses: actions/checkout@v4
105+
with:
106+
fetch-depth: 0
107+
108+
- name: Download report
109+
uses: actions/download-artifact@v4
110+
with:
111+
name: playwright-report-${{ matrix.PS_VERSION }}
112+
path: tests/UI/
113+
114+
# Nightly : Rename file
115+
- name: "Nightly : Rename file"
116+
working-directory: tests/UI/
117+
run: |
118+
mkdir -p nightly
119+
REPORT_NAME="${{ env.CAMPAIGN }}_$(date +%Y-%m-%d)-${{ matrix.PS_VERSION }}"
120+
mv report.json nightly/${REPORT_NAME}.json
121+
122+
# Nightly : Auth GCP
123+
- name: "Nightly : Auth GCP"
124+
uses: google-github-actions/auth@v1
125+
with:
126+
credentials_json: ${{ secrets.GC_SERVICE_KEY }}
127+
project_id: ${{ secrets.GC_PROJECT_ID }}
128+
129+
# Nightly : Setup GCP
130+
- name: "Nightly : Setup GCP"
131+
uses: google-github-actions/setup-gcloud@v1
132+
133+
# Nightly : Upload to Google Cloud Storage (GCS)
134+
- name: "Nightly : Upload to Google Cloud Storage (GCS)"
135+
working-directory: tests/UI/
136+
run: gsutil cp -r "nightly/**" gs://prestashop-core-nightly/reports
137+
138+
# Nightly : Push Report
139+
- name: "Nightly : Push Report"
140+
run: |
141+
REPORT_NAME="${{ env.CAMPAIGN }}_$(date +%Y-%m-%d)-${{ matrix.PS_VERSION }}"
142+
curl -v "https://api-nightly.prestashop-project.org/import/report/playwright?token=${{ secrets.NIGHTLY_TOKEN }}&filename=${REPORT_NAME}.json&campaign=${{ env.CAMPAIGN }}&platform=chromium"

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,9 @@
11
/vendor
22
.php_cs.cache
3+
4+
## UI Tests
5+
/tests/UI/.env
6+
/tests/UI/node_modules/
7+
/tests/UI/report.json
8+
/tests/UI/reports/
9+
/tests/UI/test-results/
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
import {
2+
test,
3+
expect,
4+
type Page,
5+
type BrowserContext,
6+
} from '@playwright/test';
7+
8+
import {
9+
boDashboardPage,
10+
boLoginPage,
11+
boModuleManagerPage,
12+
boProductsPage,
13+
dataModules,
14+
FakerProduct,
15+
foClassicCategoryPage,
16+
foClassicHomePage,
17+
foClassicProductPage,
18+
opsBOCatalogProduct,
19+
utilsFile,
20+
utilsTest,
21+
} from '@prestashop-core/ui-testing';
22+
23+
const baseContext: string = 'modules_ps_emailalerts_installation_uninstallAndInstallModule';
24+
25+
test.describe('Mail alerts module - Uninstall and install module', async () => {
26+
let browserContext: BrowserContext;
27+
let page: Page;
28+
let idProduct: number;
29+
let nthProduct: number|null;
30+
31+
const productOutOfStockNotAllowed: FakerProduct = new FakerProduct({
32+
name: 'Product Out of stock not allowed',
33+
type: 'standard',
34+
taxRule: 'No tax',
35+
tax: 0,
36+
quantity: 0,
37+
behaviourOutOfStock: 'Deny orders',
38+
});
39+
40+
test.beforeAll(async ({ browser }) => {
41+
browserContext = await browser.newContext();
42+
page = await browserContext.newPage();
43+
});
44+
test.afterAll(async () => {
45+
await page.close();
46+
});
47+
48+
test('PRE-Condition : Create product out of stock not allowed', async () => {
49+
await opsBOCatalogProduct.createProduct(page, productOutOfStockNotAllowed, `${baseContext}_preTest`);
50+
});
51+
52+
// BackOffice - Fetch the ID of the product
53+
test('should login in BO', async () => {
54+
await utilsTest.addContextItem(test.info(), 'testIdentifier', 'loginBO', baseContext);
55+
56+
await boLoginPage.goTo(page, global.BO.URL);
57+
await boLoginPage.successLogin(page, global.BO.EMAIL, global.BO.PASSWD);
58+
59+
const pageTitle = await boDashboardPage.getPageTitle(page);
60+
expect(pageTitle).toContain(boDashboardPage.pageTitle);
61+
});
62+
63+
test('should go to \'Catalog > Products\' page', async () => {
64+
await utilsTest.addContextItem(test.info(), 'testIdentifier', 'goToProductsPage', baseContext);
65+
66+
await boDashboardPage.goToSubMenu(
67+
page,
68+
boDashboardPage.catalogParentLink,
69+
boDashboardPage.productsLink,
70+
);
71+
72+
const pageTitle = await boProductsPage.getPageTitle(page);
73+
expect(pageTitle).toContain(boProductsPage.pageTitle);
74+
});
75+
76+
test('should filter list by \'product_name\'', async () => {
77+
await utilsTest.addContextItem(test.info(), 'testIdentifier', 'filterProductName', baseContext);
78+
79+
await boProductsPage.resetFilter(page);
80+
await boProductsPage.filterProducts(page, 'product_name', productOutOfStockNotAllowed.name, 'input');
81+
82+
const numberOfProductsAfterFilter = await boProductsPage.getNumberOfProductsFromList(page);
83+
expect(numberOfProductsAfterFilter).toEqual(1);
84+
85+
idProduct = await boProductsPage.getTextColumn(page, 'id_product', 1) as number;
86+
});
87+
88+
// BackOffice - Uninstall Module
89+
test('should go to \'Modules > Module Manager\' page', async () => {
90+
await utilsTest.addContextItem(test.info(), 'testIdentifier', 'goToModuleManagerPage', baseContext);
91+
92+
await boDashboardPage.goToSubMenu(
93+
page,
94+
boDashboardPage.modulesParentLink,
95+
boDashboardPage.moduleManagerLink,
96+
);
97+
await boModuleManagerPage.closeSfToolBar(page);
98+
99+
const pageTitle = await boModuleManagerPage.getPageTitle(page);
100+
expect(pageTitle).toContain(boModuleManagerPage.pageTitle);
101+
});
102+
103+
test(`should search the module ${dataModules.psEmailAlerts.name}`, async () => {
104+
await utilsTest.addContextItem(test.info(), 'testIdentifier', 'searchModule', baseContext);
105+
106+
const isModuleVisible = await boModuleManagerPage.searchModule(page, dataModules.psEmailAlerts);
107+
expect(isModuleVisible).toBeTruthy();
108+
});
109+
110+
test('should display the uninstall modal and cancel it', async () => {
111+
await utilsTest.addContextItem(test.info(), 'testIdentifier', 'uninstallModuleAndCancel', baseContext);
112+
113+
const textResult = await boModuleManagerPage.setActionInModule(page, dataModules.psEmailAlerts, 'uninstall', true);
114+
expect(textResult).toEqual('');
115+
116+
const isModuleVisible = await boModuleManagerPage.isModuleVisible(page, dataModules.psEmailAlerts);
117+
expect(isModuleVisible).toBeTruthy();
118+
119+
const isModalVisible = await boModuleManagerPage.isModalActionVisible(page, dataModules.psEmailAlerts, 'uninstall');
120+
expect(isModalVisible).toBeFalsy();
121+
122+
const dirExists = await utilsFile.doesFileExist(`${utilsFile.getRootPath()}/modules/${dataModules.psEmailAlerts.tag}/`);
123+
expect(dirExists).toBeTruthy();
124+
});
125+
126+
test('should uninstall the module', async () => {
127+
await utilsTest.addContextItem(test.info(), 'testIdentifier', 'uninstallModule', baseContext);
128+
129+
const successMessage = await boModuleManagerPage.setActionInModule(page, dataModules.psEmailAlerts, 'uninstall', false);
130+
expect(successMessage).toEqual(boModuleManagerPage.uninstallModuleSuccessMessage(dataModules.psEmailAlerts.tag));
131+
132+
// Check the directory `modules/Modules.psEmailAlerts.tag`
133+
const dirExists = await utilsFile.doesFileExist(`${utilsFile.getRootPath()}/modules/${dataModules.psEmailAlerts.tag}/`);
134+
expect(dirExists).toBeTruthy();
135+
});
136+
137+
// FrontOffice - Check that the module is not present
138+
test('should go to Front Office', async () => {
139+
await utilsTest.addContextItem(test.info(), 'testIdentifier', 'goToFoAfterUninstall', baseContext);
140+
141+
page = await boModuleManagerPage.viewMyShop(page);
142+
await foClassicHomePage.changeLanguage(page, 'en');
143+
144+
const isHomePage = await foClassicHomePage.isHomePage(page);
145+
expect(isHomePage).toBeTruthy();
146+
});
147+
148+
test('should go to the All Products Page', async () => {
149+
await utilsTest.addContextItem(test.info(), 'testIdentifier', 'goToAllProductsPageAfterUninstall', baseContext);
150+
151+
await foClassicHomePage.goToAllProductsPage(page);
152+
153+
const isCategoryPageVisible = await foClassicCategoryPage.isCategoryPage(page);
154+
expect(isCategoryPageVisible, 'Home category page was not opened').toBeTruthy();
155+
});
156+
157+
test('should go the the second page', async () => {
158+
await utilsTest.addContextItem(test.info(), 'testIdentifier', 'goToSecondPage', baseContext);
159+
160+
await foClassicCategoryPage.goToNextPage(page);
161+
162+
nthProduct = await foClassicCategoryPage.getNThChildFromIDProduct(page, idProduct);
163+
expect(nthProduct).not.toBeNull();
164+
});
165+
166+
test('should go to the product page', async () => {
167+
await utilsTest.addContextItem(test.info(), 'testIdentifier', 'goToProductPage', baseContext);
168+
169+
await foClassicCategoryPage.goToProductPage(page, nthProduct!);
170+
171+
const pageTitle = await foClassicProductPage.getPageTitle(page);
172+
expect(pageTitle.toUpperCase()).toContain(productOutOfStockNotAllowed.name.toUpperCase());
173+
174+
const hasFlagOutOfStock = await foClassicProductPage.hasProductFlag(page, 'out_of_stock');
175+
expect(hasFlagOutOfStock).toBeTruthy();
176+
177+
const hasBlockMailAlert = await foClassicProductPage.hasBlockMailAlert(page);
178+
expect(hasBlockMailAlert).toBeFalsy();
179+
});
180+
181+
// BackOffice - Install the module
182+
test('should go back to BO', async () => {
183+
await utilsTest.addContextItem(test.info(), 'testIdentifier', 'goBackToBo', baseContext);
184+
185+
page = await foClassicProductPage.closePage(browserContext, page, 0);
186+
await boModuleManagerPage.reloadPage(page);
187+
188+
const pageTitle = await boModuleManagerPage.getPageTitle(page);
189+
expect(pageTitle).toContain(boModuleManagerPage.pageTitle);
190+
});
191+
192+
test('should install the module', async () => {
193+
await utilsTest.addContextItem(test.info(), 'testIdentifier', 'installModule', baseContext);
194+
195+
const successMessage = await boModuleManagerPage.setActionInModule(page, dataModules.psEmailAlerts, 'install', false);
196+
expect(successMessage).toEqual(boModuleManagerPage.installModuleSuccessMessage(dataModules.psEmailAlerts.tag));
197+
198+
// Check the directory `modules/Modules.psEmailAlerts.tag`
199+
const dirExists = await utilsFile.doesFileExist(`${utilsFile.getRootPath()}/modules/${dataModules.psEmailAlerts.tag}/`);
200+
expect(dirExists).toBeTruthy();
201+
});
202+
203+
// FrontOffice - Check that the module is present
204+
test('should return to Front Office', async () => {
205+
await utilsTest.addContextItem(test.info(), 'testIdentifier', 'goToFo', baseContext);
206+
207+
page = await boModuleManagerPage.viewMyShop(page);
208+
await foClassicHomePage.changeLanguage(page, 'en');
209+
210+
const isHomePage = await foClassicHomePage.isHomePage(page);
211+
expect(isHomePage).toBeTruthy();
212+
});
213+
214+
test('should return to the All Products Page', async () => {
215+
await utilsTest.addContextItem(test.info(), 'testIdentifier', 'goToAllProductsPage', baseContext);
216+
217+
await foClassicHomePage.goToAllProductsPage(page);
218+
219+
const isCategoryPageVisible = await foClassicCategoryPage.isCategoryPage(page);
220+
expect(isCategoryPageVisible, 'Home category page was not opened').toBeTruthy();
221+
});
222+
223+
test('should return to the product page', async () => {
224+
await utilsTest.addContextItem(test.info(), 'testIdentifier', 'goToProductPageWithMailAlert', baseContext);
225+
226+
await foClassicCategoryPage.goToNextPage(page);
227+
await foClassicCategoryPage.goToProductPage(page, nthProduct!);
228+
229+
const pageTitle = await foClassicProductPage.getPageTitle(page);
230+
expect(pageTitle.toUpperCase()).toContain(productOutOfStockNotAllowed.name.toUpperCase());
231+
232+
const hasFlagOutOfStock = await foClassicProductPage.hasProductFlag(page, 'out_of_stock');
233+
expect(hasFlagOutOfStock).toBeTruthy()
234+
235+
const hasBlockMailAlert = await foClassicProductPage.hasBlockMailAlert(page);
236+
expect(hasBlockMailAlert).toBeTruthy();
237+
});
238+
239+
test('POST-Condition : Delete product out of stock not allowed', async () => {
240+
await opsBOCatalogProduct.deleteProduct(page, productOutOfStockNotAllowed, `${baseContext}_postTest_0`);
241+
});
242+
});

0 commit comments

Comments
 (0)