first commit

This commit is contained in:
2024-11-05 12:22:50 +01:00
commit e5682a3912
19641 changed files with 2948548 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
# E2E tests
This folder contains tests about ps_banner module.
## Supported versions
These tests can be run on `1.7.7.x` and `1.7.6.x` PrestaShop versions.
## Stack
In these tests, we used the actual stack :
- [prestashop_test_lib](https://www.npmjs.com/package/prestashop_test_lib) which uses [playwright](https://playwright.dev/) as a node library to automate browsers.
- [mocha](https://mochajs.org/) as a test framework.
- [chai](https://www.chaijs.com/) as an assertion library.
- [js-image-generator](https://www.npmjs.com/package/js-image-generator) as a node library to generate fake images for tests.
## Running tests
Before running tests, you should run `npm install`, to install all dependencies.
### Running all tests
```shell
PS_VERSION='1.7.7' URL_FO='http://localhost.com/' npm run e2e-tests
```
### Running all tests with fast fail mode
The fast fail mode give us the possibility to abort the run after first test failure. It uses the --bail option from [mocha](https://mochajs.org/#command-line-usage).
This mode is mostly used in CI (like here in Github Actions), to stop the tests as quickly as possible.
```shell
PS_VERSION='1.7.7' URL_FO='http://localhost/prestashop/' npm run e2e-tests-fast-fail
```
### Env variables
Some variables can be used to run tests:
| Parameter | Description |
|---------------------|----------------------------------------------------- |
| PS_VERSION | PrestaShop minor version (not patch version) (default to **`1.7.7`**)|
| URL_FO | URL of your PrestaShop website Front Office (default to **`http://localhost/prestashop/`**) |
| URL_BO | URL of your PrestaShop website Back Office (default to **`URL_FO + admin-dev/`**) |
| BROWSER | Specific browser to launch for tests (default to **`chromium`**) |
| HEADLESS | Boolean to run tests in [headless mode](https://en.wikipedia.org/wiki/Headless_software) or not (default to **`true`**) |
For more variables, please take a look on global vars on [prestashop_test_lib](https://github.com/PrestaShopCorp/prestashop_test_lib/blob/master/kernel/utils/globals.js).
Enjoy :wink: :v:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
{
"name": "ps_banner_e2e_tests",
"version": "1.0.0",
"description": "Tests E2E for ps_banner modules",
"scripts": {
"e2e-tests": "./node_modules/mocha/bin/mocha --recursive --file ./node_modules/prestashop_test_lib/kernel/utils/setup.js scenarios/*",
"e2e-tests-fast-fail": "./node_modules/mocha/bin/mocha --bail --recursive --file ./node_modules/prestashop_test_lib/kernel/utils/setup.js scenarios/*",
"lint": "eslint --ignore-path .gitignore .",
"lint-fix": "eslint --ignore-path .gitignore --fix ."
},
"_moduleAliases": {
"@versions": "versions",
"@scenarios": "scenarios",
"@utils": "utils"
},
"keywords": [
"e2e",
"tests",
"playwright"
],
"author": "",
"license": "ISC",
"dependencies": {
"chai": "^4.2.0",
"eslint-config-prestashop": "0.0.2",
"js-image-generator": "^1.0.3",
"mocha": "^8.2.1",
"mochawesome": "^6.2.1",
"module-alias": "^2.2.2",
"prestashop_test_lib": "0.0.14"
},
"devDependencies": {
"babel-eslint": "^10.1.0",
"eslint": "^5.4.0",
"eslint-config-airbnb-base": "^13.1.0",
"eslint-plugin-import": "^2.22.1"
}
}

View File

@@ -0,0 +1,163 @@
require('module-alias/register');
const {expect} = require('chai');
const browserHelper = require('prestashop_test_lib/kernel/utils/helpers.js');
const configClassMap = require('@utils/configClassMap.js');
const imageHelper = require('@utils/imageHelper.js');
const fileHelper = require('@utils/fileHelper');
// Get resolver
const VersionSelectResolver = require('prestashop_test_lib/kernel/resolvers/versionSelectResolver.js');
const versionSelectResolver = new VersionSelectResolver(global.PS_VERSION, configClassMap);
// Import pages
const loginPage = versionSelectResolver.require('BO/login/index.js');
const dashboardPage = versionSelectResolver.require('BO/dashboard/index.js');
const moduleManagerPage = versionSelectResolver.require('BO/modules/moduleManager/index.js');
const psBannerModulePage = versionSelectResolver.require('BO/modules/ps_banner/index.js');
const homePage = versionSelectResolver.require('FO/home/index.js');
// Browser vars
let browserContext;
let page;
const moduleToInstall = {
name: 'Banner',
tag: 'ps_banner',
};
const moduleConfiguration = {
en: {
langId: 1,
imagePath: './image_en.png',
link: global.FO.URL,
description: 'This is a description for module ps_banner',
},
fr: {
langId: 2,
imagePath: './image_fr.png',
link: global.FO.URL,
description: 'Ceci est une description du module ps_banner',
},
};
describe('Go to ps_banner configuration page', async () => {
// before and after functions
before(async function () {
browserContext = await browserHelper.createBrowserContext(this.browser);
page = await browserHelper.newTab(browserContext);
// Create images for test
await Promise.all([
imageHelper.generateImage(moduleConfiguration.en.imagePath),
imageHelper.generateImage(moduleConfiguration.fr.imagePath),
]);
});
after(async () => {
await browserHelper.closeBrowserContext(browserContext);
// Delete images after test
await Promise.all([
fileHelper.deleteFile(moduleConfiguration.en.imagePath),
fileHelper.deleteFile(moduleConfiguration.fr.imagePath),
]);
});
it('should go to login page', async () => {
await loginPage.goTo(page, global.BO.URL);
const pageTitle = await loginPage.getPageTitle(page);
await expect(pageTitle).to.contains(loginPage.pageTitle);
});
it('should check PS version', async () => {
const psVersion = await loginPage.getPrestashopVersion(page);
await expect(psVersion).to.contains(global.PS_VERSION);
});
it('should login into BO with default user', async () => {
await loginPage.login(page, global.BO.EMAIL, global.BO.PASSWD);
await dashboardPage.closeOnboardingModal(page);
const pageTitle = await dashboardPage.getPageTitle(page);
await expect(pageTitle).to.contains(dashboardPage.pageTitle);
});
it('should go to module manager page', async () => {
await dashboardPage.goToSubMenu(
page,
dashboardPage.modulesParentLink,
dashboardPage.moduleManagerLink,
);
const pageTitle = await moduleManagerPage.getPageTitle(page);
await expect(pageTitle).to.contain(moduleManagerPage.pageTitle);
});
it('should check that the module was installed', async () => {
const isModuleVisible = await moduleManagerPage.searchModule(
page,
moduleToInstall.tag,
moduleToInstall.name,
);
await expect(isModuleVisible).to.be.true;
});
it('should check that the module is enabled', async () => {
const isModuleEnabled = await moduleManagerPage.isModuleEnabled(page, moduleToInstall.name);
await expect(isModuleEnabled).to.be.true;
});
it('should go to configuration page', async () => {
await moduleManagerPage.goToConfigurationPage(page, moduleToInstall.name);
// Check configuration page
const pageTitle = await psBannerModulePage.getPageTitle(page);
await expect(pageTitle).to.contain(psBannerModulePage.pageTitle);
// Check module name
const pageSubtitle = await psBannerModulePage.getPageSubtitle(page);
await expect(pageSubtitle).to.contain(moduleToInstall.name);
});
it('should set module configuration', async () => {
const textResult = await psBannerModulePage.setConfiguration(page, moduleConfiguration);
await expect(textResult).to.contain(psBannerModulePage.updatedSettingSuccessfulMessage);
});
it('should view my shop and check that banner exist', async () => {
page = await psBannerModulePage.viewMyShop(page);
const bannerExists = await homePage.isBannerVisible(page);
await expect(bannerExists).to.be.true;
});
it('should check banner link and description in english', async () => {
await homePage.changeLanguage(page, 'en');
// Check banner link
const bannerLink = await homePage.getBannerLink(page);
await expect(bannerLink).to.equal(moduleConfiguration.en.link);
// Check banner description
const bannerDescription = await homePage.getBannerDescription(page);
await expect(bannerDescription).to.equal(moduleConfiguration.en.description);
});
it('should check banner link and description in french', async () => {
await homePage.changeLanguage(page, 'fr');
// Check banner link
const bannerLink = await homePage.getBannerLink(page);
await expect(bannerLink).to.equal(moduleConfiguration.fr.link);
// Check banner description
const bannerDescription = await homePage.getBannerDescription(page);
await expect(bannerDescription).to.equal(moduleConfiguration.fr.description);
});
});

View File

@@ -0,0 +1,110 @@
require('module-alias/register');
const {expect} = require('chai');
const browserHelper = require('prestashop_test_lib/kernel/utils/helpers.js');
const configClassMap = require('@utils/configClassMap.js');
// Get resolver
const VersionSelectResolver = require('prestashop_test_lib/kernel/resolvers/versionSelectResolver.js');
const versionSelectResolver = new VersionSelectResolver(global.PS_VERSION, configClassMap);
// Import pages
const loginPage = versionSelectResolver.require('BO/login/index.js');
const dashboardPage = versionSelectResolver.require('BO/dashboard/index.js');
const moduleManagerPage = versionSelectResolver.require('BO/modules/moduleManager/index.js');
const homePage = versionSelectResolver.require('FO/home/index.js');
// Browser vars
let browserContext;
let page;
const moduleToInstall = {
name: 'Banner',
tag: 'ps_banner',
};
describe('Disable and enable module', async () => {
// before and after functions
before(async function () {
browserContext = await browserHelper.createBrowserContext(this.browser);
page = await browserHelper.newTab(browserContext);
});
after(async () => {
await browserHelper.closeBrowserContext(browserContext);
});
it('should go to login page', async () => {
await loginPage.goTo(page, global.BO.URL);
const pageTitle = await loginPage.getPageTitle(page);
await expect(pageTitle).to.contains(loginPage.pageTitle);
});
it('should login into BO with default user', async () => {
await loginPage.login(page, global.BO.EMAIL, global.BO.PASSWD);
await dashboardPage.closeOnboardingModal(page);
const pageTitle = await dashboardPage.getPageTitle(page);
await expect(pageTitle).to.contains(dashboardPage.pageTitle);
});
it('should go to module manager page', async () => {
await dashboardPage.goToSubMenu(
page,
dashboardPage.modulesParentLink,
dashboardPage.moduleManagerLink,
);
const pageTitle = await moduleManagerPage.getPageTitle(page);
await expect(pageTitle).to.contain(moduleManagerPage.pageTitle);
});
it('should check that the module was installed', async () => {
const isModuleVisible = await moduleManagerPage.searchModule(
page,
moduleToInstall.tag,
moduleToInstall.name,
);
await expect(isModuleVisible).to.be.true;
});
it('should check that the module is enabled', async () => {
const isModuleEnabled = await moduleManagerPage.isModuleEnabled(page, moduleToInstall.name);
await expect(isModuleEnabled).to.be.true;
});
it('should disable module', async () => {
const textResult = await moduleManagerPage.disableModule(page, moduleToInstall.tag, moduleToInstall.name);
await expect(textResult).to.contain(moduleManagerPage.successfulDisableMessage(moduleToInstall.tag));
});
it('should view my shop and check that banner don\'t exist', async () => {
page = await moduleManagerPage.viewMyShop(page);
const bannerExists = await homePage.isBannerVisible(page);
await expect(bannerExists).to.be.false;
});
it('should go back to BO', async () => {
page = await homePage.closePage(browserContext, page, 0);
const pageTitle = await moduleManagerPage.getPageTitle(page);
await expect(pageTitle).to.contain(moduleManagerPage.pageTitle);
});
it('should enable module', async () => {
const textResult = await moduleManagerPage.enableModule(page, moduleToInstall.name);
await expect(textResult).to.contain(moduleManagerPage.successfulEnableMessage(moduleToInstall.tag));
});
it('should view my shop and check that banner exist', async () => {
page = await moduleManagerPage.viewMyShop(page);
const bannerExists = await homePage.isBannerVisible(page);
await expect(bannerExists).to.be.true;
});
});

View File

@@ -0,0 +1,18 @@
module.exports = [
{
file: 'BO/modules/ps_banner/index.js',
versions: {
'1.7.6': '@versions/177/BO/modules/ps_banner/index.js',
'1.7.7': '@versions/177/BO/modules/ps_banner/index.js',
'1.7.8': '@versions/177/BO/modules/ps_banner/index.js',
},
},
{
file: 'FO/home/index.js',
versions: {
'1.7.6': '@versions/177/FO/home/index.js',
'1.7.7': '@versions/177/FO/home/index.js',
'1.7.8': '@versions/177/FO/home/index.js',
},
},
];

View File

@@ -0,0 +1,14 @@
const fs = require('fs');
module.exports = {
/**
* Delete File if exist
* @param pathToFile
* @return {Promise<void>}
*/
async deleteFile(pathToFile) {
if (fs.existsSync(pathToFile)) {
fs.unlinkSync(pathToFile);
}
},
};

View File

@@ -0,0 +1,18 @@
const fs = require('fs');
const imgGen = require('js-image-generator');
module.exports = {
/**
* Generate image
* @param imageName
* @param width
* @param height
* @param quality
* @return {Promise<void>}
*/
async generateImage(imageName, width = 200, height = 200, quality = 1) {
await imgGen.generateImage(width, height, quality, (err, image) => {
fs.writeFileSync(imageName, image.data);
});
},
};

View File

@@ -0,0 +1,121 @@
// Get resolver
const VersionSelectResolver = require('prestashop_test_lib/kernel/resolvers/versionSelectResolver');
const versionSelectResolver = new VersionSelectResolver(global.PS_VERSION);
// Import BOBasePage
const ModuleConfigurationPage = versionSelectResolver.require('BO/modules/moduleConfiguration/index.js');
class PS_BANNER extends ModuleConfigurationPage.constructor {
constructor() {
super();
this.updatedSettingSuccessfulMessage = 'The settings have been updated.';
// Selectors
this.titleBlock = 'h2.page-title';
this.subtitleBlock = 'h4.page-subtitle';
// Alert success selector
this.alertSuccessBlock = '.alert-success.module_confirmation';
// Form selectors
this.moduleForm = '#module_form';
this.bannerImageSelectButton = langId => `#BANNER_IMG_${langId}-selectbutton`;
this.bannerLinkInput = langId => `#BANNER_LINK_${langId}`;
this.bannerDescriptionInput = langId => `#BANNER_DESC_${langId}`;
this.saveButton = '#module_form_submit_btn';
// Change languages selector
this.dropdownLangButton = `${this.moduleForm} button.dropdown-toggle`;
this.dropdownLangItemLink = langId => `#dropdown-lang-item-link-${langId}`;
}
// Functions
/**
* Change form language
* @param page
* @param langId
* @return {Promise<void>}
*/
async changeLanguage(page, langId) {
await Promise.all([
page.click(this.dropdownLangButton),
this.waitForVisibleSelector(page, this.dropdownLangItemLink(langId)),
]);
await page.click(this.dropdownLangItemLink(langId));
}
/**
* Upload image for a specific language
* @param page
* @param imagePath
* @param langId
* @return {Promise<void>}
*/
async uploadImagePath(page, imagePath, langId) {
// Set value when fileChooser is open
page.once('filechooser', async (fileChooser) => {
await fileChooser.setFiles(imagePath);
});
await page.click(this.bannerImageSelectButton(langId));
}
/**
* Set link for a specific language
* @param page
* @param link
* @param langId
* @return {Promise<void>}
*/
async setBannerLink(page, link, langId) {
await this.setValue(page, this.bannerLinkInput(langId), link);
}
/**
* Set description for a specific language
* @param page
* @param description
* @param langId
* @return {Promise<void>}
*/
async setBannerDescription(page, description, langId) {
await this.setValue(page, this.bannerDescriptionInput(langId), description);
}
/**
* Fill all inputs in form in a specific language
* @param page
* @param configuration
* @return {Promise<void>}
*/
async fillSpecificLanguageForm(page, configuration) {
await this.changeLanguage(page, configuration.langId);
await this.uploadImagePath(page, configuration.imagePath, configuration.langId);
await this.setBannerLink(page, configuration.link, configuration.langId);
await this.setBannerDescription(page, configuration.description, configuration.langId);
}
/**
* Configure module in 2 languages en and fr
* @param page
* @param configuration
* @return {Promise<string>}
*/
async setConfiguration(page, configuration) {
// Fill form in lang=en
await this.fillSpecificLanguageForm(page, configuration.en);
// Fill form in lang=fr
await this.fillSpecificLanguageForm(page, configuration.fr);
// Save for and get successful message
await this.clickAndWaitForNavigation(page, this.saveButton);
return this.getTextContent(page, this.alertSuccessBlock);
}
}
module.exports = new PS_BANNER();

View File

@@ -0,0 +1,31 @@
// Get resolver
const CommonPage = require('prestashop_test_lib/versions/commonPage.js');
module.exports = class FoBasePage extends CommonPage {
constructor() {
super();
// Selectors
this.languageSelectorDiv = '#_desktop_language_selector';
this.languageSelectorExpandIcon = `${this.languageSelectorDiv} i.expand-more`;
this.languageSelectorMenuItemLink = language => `${this.languageSelectorDiv}`
+ ` ul li a[data-iso-code='${language}']`;
}
// Functions
/**
* Change language in FO
* @param page
* @param lang
* @return {Promise<void>}
*/
async changeLanguage(page, lang = 'en') {
await Promise.all([
page.click(this.languageSelectorExpandIcon),
this.waitForVisibleSelector(page, this.languageSelectorMenuItemLink(lang)),
]);
await this.clickAndWaitForNavigation(page, this.languageSelectorMenuItemLink(lang));
}
};

View File

@@ -0,0 +1,50 @@
const CommonPage = require('@versions/177/FO/foBasePage.js');
class Home extends CommonPage {
constructor() {
super();
// Selectors
this.bannerLink = 'a.banner';
this.bannerImage = `${this.bannerLink} img`;
}
// Functions
/**
* Check is banner is displayed
* @param page
* @return {Promise<boolean>}
*/
isBannerVisible(page) {
return this.elementVisible(page, this.bannerLink, 2000);
}
/**
* Get banner link
* @param page
* @return {Promise<string>}
*/
getBannerLink(page) {
return this.getAttributeContent(page, this.bannerLink, 'href');
}
/**
* Get banner description
* @param page
* @return {Promise<string>}
*/
getBannerDescription(page) {
return this.getAttributeContent(page, this.bannerLink, 'title');
}
/**
* Check if banner image is visible
* @param page
* @return {Promise<boolean>}
*/
bannerHasImage(page) {
return this.elementVisible(page, this.bannerImage, 2000);
}
}
module.exports = new Home();

View File

@@ -0,0 +1,35 @@
<?php
/*
* 2007-2015 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2015 PrestaShop SA
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,28 @@
#!/bin/bash
PS_VERSION=$1
set -e
# Docker images prestashop/prestashop may be used, even if the shop remains uninstalled
echo "Pull PrestaShop files (Tag ${PS_VERSION})"
docker rm -f temp-ps || true
docker volume rm -f ps-volume || true
docker run -tid --rm -v ps-volume:/var/www/html --name temp-ps prestashop/prestashop:$PS_VERSION
# Clear previous instance of the module in the PrestaShop volume
echo "Clear previous module"
docker exec -t temp-ps rm -rf /var/www/html/modules/ps_banner
# Run a container for PHPStan, having access to the module content and PrestaShop sources.
# This tool is outside the composer.json because of the compatibility with PHP 5.6
echo "Run PHPStan using phpstan-${PS_VERSION}.neon file"
docker run --rm --volumes-from temp-ps \
-v $PWD:/var/www/html/modules/ps_banner \
-e _PS_ROOT_DIR_=/var/www/html \
--workdir=/var/www/html/modules/ps_banner phpstan/phpstan:0.12 \
analyse \
--configuration=/var/www/html/modules/ps_banner/tests/phpstan/phpstan-$PS_VERSION.neon

View File

@@ -0,0 +1,35 @@
<?php
/*
* 2007-2015 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2015 PrestaShop SA
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,6 @@
includes:
- %currentWorkingDirectory%/tests/phpstan/phpstan.neon
parameters:
ignoreErrors:
- '#Call to method assign\(\) on an unknown class Smarty_Data.#'

View File

@@ -0,0 +1,6 @@
includes:
- %currentWorkingDirectory%/tests/phpstan/phpstan.neon
parameters:
ignoreErrors:
- '#Call to method assign\(\) on an unknown class Smarty_Data.#'

View File

@@ -0,0 +1,6 @@
includes:
- %currentWorkingDirectory%/tests/phpstan/phpstan.neon
parameters:
ignoreErrors:
- '#Call to method assign\(\) on an unknown class Smarty_Data.#'

View File

@@ -0,0 +1,5 @@
includes:
- %currentWorkingDirectory%/tests/phpstan/phpstan.neon
parameters:
ignoreErrors:

View File

@@ -0,0 +1,5 @@
includes:
- %currentWorkingDirectory%/tests/phpstan/phpstan.neon
parameters:
ignoreErrors:

View File

@@ -0,0 +1,5 @@
includes:
- %currentWorkingDirectory%/tests/phpstan/phpstan.neon
parameters:
ignoreErrors:

View File

@@ -0,0 +1,5 @@
includes:
- %currentWorkingDirectory%/tests/phpstan/phpstan.neon
parameters:
ignoreErrors:

View File

@@ -0,0 +1,5 @@
includes:
- %currentWorkingDirectory%/tests/phpstan/phpstan.neon
parameters:
ignoreErrors:

View File

@@ -0,0 +1,5 @@
includes:
- %currentWorkingDirectory%/tests/phpstan/phpstan.neon
parameters:
ignoreErrors:

View File

@@ -0,0 +1,10 @@
includes:
- %currentWorkingDirectory%/vendor/prestashop/php-dev-tools/phpstan/ps-module-extension.neon
parameters:
paths:
# From PHPStan 0.12, paths to check are relative to the neon file
- ../../ps_banner.php
ignoreErrors:
reportUnmatchedIgnoredErrors: false
level: 5