Skip to content

Commit 7c5b338

Browse files
committed
Added UI Tests
1 parent 4e1496d commit 7c5b338

9 files changed

Lines changed: 2926 additions & 0 deletions

File tree

.github/workflows/ui-test.yml

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
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: Rights
43+
run: chmod -R 777 ./mails
44+
45+
- name: Setup PHP
46+
uses: shivammathur/setup-php@v2
47+
with:
48+
php-version: ${{ matrix.PHP_VERSION }}
49+
50+
- name: Install dependencies
51+
run: composer install --no-dev && composer dump-autoload -o --no-dev
52+
53+
- name: Start containers
54+
working-directory: tests/UI/
55+
run: |
56+
docker compose -f "docker-compose.yml" up -d --build
57+
bash -c 'while [[ "$(curl -L -s -o /dev/null -w %{http_code} http://localhost/en/)" != "200" ]]; do sleep 5; done'
58+
59+
- name: Install dependencies
60+
working-directory: tests/UI/
61+
run: npm ci
62+
63+
- name: Install Playwright Browsers
64+
working-directory: tests/UI/
65+
run: npx playwright install chromium --with-deps
66+
67+
- name: Run Playwright tests
68+
working-directory: tests/UI/
69+
run: npx playwright test
70+
71+
- name: Export Docker errors
72+
working-directory: tests/UI/
73+
if: always()
74+
run: docker compose logs --no-color >& docker-compose.log
75+
76+
- name: Upload artifact
77+
uses: actions/upload-artifact@v4
78+
if: always()
79+
with:
80+
name: playwright-report-${{ matrix.PS_VERSION }}
81+
path: |
82+
tests/UI/reports/
83+
tests/UI/report.json
84+
tests/UI/docker-compose.log
85+
retention-days: 30
86+
87+
nightly:
88+
name: Nightly Report
89+
if: ${{ github.event_name == 'schedule' }}
90+
needs:
91+
- ui_test
92+
runs-on: ubuntu-latest
93+
strategy:
94+
fail-fast: false
95+
matrix:
96+
PS_VERSION:
97+
- '1.7.7.8'
98+
- '1.7.8.11'
99+
- '8.0.5'
100+
- '8.1.6'
101+
- 'nightly'
102+
permissions:
103+
contents: 'read'
104+
id-token: 'write'
105+
steps:
106+
- name: Checkout
107+
uses: actions/checkout@v4
108+
with:
109+
fetch-depth: 0
110+
111+
- name: Download report
112+
uses: actions/download-artifact@v4
113+
with:
114+
name: playwright-report-${{ matrix.PS_VERSION }}
115+
path: tests/UI/
116+
117+
# Nightly : Rename file
118+
- name: "Nightly : Rename file"
119+
working-directory: tests/UI/
120+
run: |
121+
mkdir -p nightly
122+
REPORT_NAME="${{ env.CAMPAIGN }}_$(date +%Y-%m-%d)-${{ matrix.PS_VERSION }}"
123+
mv report.json nightly/${REPORT_NAME}.json
124+
125+
# Nightly : Auth GCP
126+
- name: "Nightly : Auth GCP"
127+
uses: google-github-actions/auth@v1
128+
with:
129+
credentials_json: ${{ secrets.GC_SERVICE_KEY }}
130+
project_id: ${{ secrets.GC_PROJECT_ID }}
131+
132+
# Nightly : Setup GCP
133+
- name: "Nightly : Setup GCP"
134+
uses: google-github-actions/setup-gcloud@v1
135+
136+
# Nightly : Upload to Google Cloud Storage (GCS)
137+
- name: "Nightly : Upload to Google Cloud Storage (GCS)"
138+
working-directory: tests/UI/
139+
run: gsutil cp -r "nightly/**" gs://prestashop-core-nightly/reports
140+
141+
# Nightly : Push Report
142+
- name: "Nightly : Push Report"
143+
run: |
144+
REPORT_NAME="${{ env.CAMPAIGN }}_$(date +%Y-%m-%d)-${{ matrix.PS_VERSION }}"
145+
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)