Skip to content

Commit

Permalink
Add layout test service (#11)
Browse files Browse the repository at this point in the history
* Establish node version

* Initial work on layout test service

* Fix eslint

* Add option to check elements count

* Test element's (x,y) position

* Fix display
  • Loading branch information
MikeyZat authored Aug 21, 2021
1 parent ce85643 commit 55b6e74
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 16 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module.exports = {
es2021: true,
node: true,
},
extends: ['prettier'],
extends: ['eslint:recommended', 'prettier'],
plugins: ['prettier', 'import'],
parserOptions: {
ecmaVersion: 12,
Expand Down
1 change: 1 addition & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodejs 16.4.1
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const main = async (fileName, options) => {
}

if (Array.isArray(tests)) {
for (test of tests) {
for (let test of tests) {
await handleTest(test, mergedGlobalConfig);
}

Expand Down
3 changes: 2 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion src/services/common/genericService.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,17 @@ const genericService = async (localConfig, globalConfig, runTestsFunction) => {
logger.debug(config);

if (config.run !== false) {
if (localConfig.name)
logger.info(`Starting test case suite: ${localConfig.name}`);

await runTestsFunction(config, testCases);
}

revertLoggerLevel(oldLogLevel);
} catch (e) {
logger.trace(e);
logger.error(
`Error occured while running service for styles tests: ${
`Error occured while running test service for test case: ${
localConfig.name || globalConfig.name
}`
);
Expand Down
105 changes: 100 additions & 5 deletions src/services/layoutService/testsRunner.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,117 @@
// Created by Mikołaj Zatorski c. 2021

const tap = require('tap');
const { runPuppeteerTests } = require('../common/commonPuppeteer');
const { logger } = require('../../utils/logger');

const runLayoutTests = async (config, testCases) =>
await runPuppeteerTests(config, testCases, runTestCases);

const runTestCases = async (page, testCases) => {
for (testCase of testCases) {
for (let testCase of testCases) {
await runTestCase(page, testCase);
}
};

const runTestCase = async (page, testCase) => {
logger.info(
"Welcome to layout test service - it's finally coming in in the next release"
const { selector, xpath, ...tests } = testCase;
const { position, contains: containCases } = tests;
const locator = selector || xpath;

await tap.test(
`[LAYOUT SERVICE]: Checking element: ${locator}`,
async (t) => {
let element;
try {
element = await getElement(page, locator, !!selector);
} catch (err) {
logger.trace(err);
element = null;
}

if (!element) {
t.fail(`Element: ${locator} doesn't exist`);
t.end();
return;
}

if (position) {
const { x, y } = position;
if (typeof x !== 'number' || x < 0 || typeof y !== 'number' || y < 0) {
t.fail('Either x or y value is not a valid number');
} else {
const {
x: actualX,
y: actualY,
width,
height,
} = await element.boundingBox();
const offsetX = x - actualX;
const offsetY = y - actualY;
const isInside =
offsetX >= 0 &&
offsetX <= width &&
offsetY >= 0 &&
offsetY <= height;
tap.ok(
isInside,
`check if element ${locator} is visible at (x,y) = (${x}, ${y}).`
);
}
}

if (containCases) {
for (let elementToFind of containCases) {
const {
selector: childSelector,
xpath: childXpath,
count = 1,
} = elementToFind;
const childLocator = childSelector || childXpath;
try {
const multiple = true;
const foundChildElements = await getElement(
element,
childLocator,
!!childSelector,
multiple
);
const actualCount = foundChildElements?.length;
t.same(
actualCount,
count,
`check if element ${childLocator} appears ${count} times within element ${locator}`
);
} catch (err) {
logger.trace(err);
t.fail(`Element: ${childLocator} doesn't exist within ${locator}`);
}
}
}
t.end();
}
);
console.log(page);
console.log(testCase);
};

const getElement = async (
parentElement,
elementSelector,
isSelector,
multiple = false
) =>
isSelector
? await getElementWithSelector(parentElement, elementSelector, multiple)
: await getElementWithxPath(parentElement, elementSelector, multiple);

const getElementWithSelector = async (parentElement, selector, multiple) =>
multiple ? await parentElement.$$(selector) : await parentElement.$(selector);

const getElementWithxPath = async (parentElement, xPath, multiple) => {
const nodeHandle = await parentElement.$x(xPath);
if (multiple) {
return nodeHandle;
}
return nodeHandle[0];
};

module.exports = {
Expand Down
14 changes: 8 additions & 6 deletions src/services/stylesService/testsRunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,36 @@ const runStylesTests = async (config, testCases) =>
await runPuppeteerTests(config, testCases, runTestCases);

const runTestCases = async (page, testCases) => {
for (testCase of testCases) {
for (let testCase of testCases) {
await runTestCase(page, testCase);
}
};

const runTestCase = async (page, testCase) => {
const { selector, xpath, ...expectedStyles } = testCase;
const locator = selector || xpath;

await tap.test(
`[STYLES SERVICE]: Checking element: ${selector || xpath}`,
`[STYLES SERVICE]: Checking element: ${locator}`,
async (t) => {
let actualStyles;
try {
actualStyles = await getStylesToCompare(
page,
selector || xpath,
locator,
expectedStyles,
!!selector
);
} catch (err) {
logger.trace(err);
actualStyles = false;
}
t.ok(actualStyles, `check if element ${selector || xpath} exists`);
t.ok(actualStyles, `check if element ${locator} exists`);
if (actualStyles) {
t.same(
normalizeStyles(actualStyles),
normalizeStyles(expectedStyles),
`compare if element ${selector || xpath} styles match`
`compare if element ${locator} styles match`
);
}
t.end();
Expand All @@ -64,9 +65,10 @@ const getStylesWithxPath = async (page, xPath, expectedStyles) => {
};

const getElementStyles = (node, testedStyles) => {
// eslint-disable-next-line
const nodeStyles = window.getComputedStyle(node);
const shapedStyles = {};
for (property in testedStyles) {
for (let property in testedStyles) {
shapedStyles[property] = nodeStyles.getPropertyValue(property);
}
return shapedStyles;
Expand Down
2 changes: 1 addition & 1 deletion src/utils/setExitCode.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
const tap = require('tap');

const setExitCode = () => {
process.on('exit', (code) => {
process.on('exit', () => {
if (tap.counts.total === 0) {
console.log('No test cases run :(');
console.log('Exiting with status code 1');
Expand Down

0 comments on commit 55b6e74

Please sign in to comment.