diff --git a/lib/tasks/tests/visual/run.js b/lib/tasks/tests/visual/run.js index f955fc6521c6436fb397a2e02a04324c5d254b81..1c09af9e3fb6135ddf663577365d92b915c6e016 100644 --- a/lib/tasks/tests/visual/run.js +++ b/lib/tasks/tests/visual/run.js @@ -91,8 +91,7 @@ export default (gulp, config, args) => { /* Start Gemini and return runner upon finish */ return new Gemini(gemini).test(`${config.tests.visual}/suites`, { - reporters: [process.env.CI ? "flat" : "html"], - grep: args.grep ? new RegExp(args.grep, "i") : null, + reporters: ["flat"].concat(process.env.CI ? [] : ["html"]), browsers: args.browsers ? [].concat(args.browsers) : null }) diff --git a/scripts/build b/scripts/build index 1f77f8097f2e81698cb53076036ba3301996dfdd..8037cbda3efc4299dc2e24828e3dd4125f6a12f8 100755 --- a/scripts/build +++ b/scripts/build @@ -28,4 +28,4 @@ if [[ ! -d `npm bin` ]]; then fi # Run command -`npm bin`/gulp build --clean --optimize --revision $@ +`npm bin`/gulp build --clean --optimize --revision "$@" diff --git a/scripts/clean b/scripts/clean index 9cb9d0f33c911533c8dc1d73159f01824d766013..309567950cfa058d306b8e2bfd07ee86eb49685b 100755 --- a/scripts/clean +++ b/scripts/clean @@ -28,4 +28,4 @@ if [[ ! -d `npm bin` ]]; then fi # Run command -`npm bin`/gulp clean $@ +`npm bin`/gulp clean "$@" diff --git a/scripts/start b/scripts/start index 385e72923c24fba8c67f4a4c40de85569df136bf..0dc23e37c0051f0b6cce115a2618f72a475a1017 100755 --- a/scripts/start +++ b/scripts/start @@ -28,4 +28,4 @@ if [[ ! -d `npm bin` ]]; then fi # Run command -`npm bin`/gulp watch --no-lint $@ +`npm bin`/gulp watch --no-lint "$@" diff --git a/scripts/test/visual/run b/scripts/test/visual/run index a5691bb5dc5219e279000ccd80ba1a539eb27d70..04c45871e6ecab1d8862a8fc17af9a462658b5a1 100755 --- a/scripts/test/visual/run +++ b/scripts/test/visual/run @@ -28,4 +28,4 @@ if [[ ! -d `npm bin` ]]; then fi # Run command -`npm bin`/gulp tests:visual:run --clean $@ +`npm bin`/gulp tests:visual:run --clean "$@" diff --git a/scripts/test/visual/session b/scripts/test/visual/session index 61803861c8baf726ae5e86d341eb26c7bde7a399..5d30bd2e1ad45044eace8f2fe5c30047cf69915f 100755 --- a/scripts/test/visual/session +++ b/scripts/test/visual/session @@ -28,4 +28,4 @@ if [[ ! -d `npm bin` ]]; then fi # Run command -`npm bin`/gulp tests:visual:session $@ +`npm bin`/gulp tests:visual:session "$@" diff --git a/scripts/test/visual/update b/scripts/test/visual/update index eabae85b3f315fc5bb2cc2fb0abb12371b0b6212..61789f24d5c1aa237d58e64ede627ff0e53ed955 100755 --- a/scripts/test/visual/update +++ b/scripts/test/visual/update @@ -28,4 +28,4 @@ if [[ ! -d `npm bin` ]]; then fi # Run command -`npm bin`/gulp tests:visual:update $@ +`npm bin`/gulp tests:visual:update "$@" diff --git a/tests/visual/helpers/spec.js b/tests/visual/helpers/spec.js index 760ca5ba42b281708f31297f686259fb1d03d1bc..2ab6eeadd062d5b938cbc7eec38a149a2573d871 100644 --- a/tests/visual/helpers/spec.js +++ b/tests/visual/helpers/spec.js @@ -22,6 +22,14 @@ import config from "../config.json" import path from "path" +import yargs from "yargs" + +/* ---------------------------------------------------------------------------- + * Configuration and arguments + * ------------------------------------------------------------------------- */ + +/* Parse arguments from command line */ +const args = yargs.argv /* ---------------------------------------------------------------------------- * Functions @@ -61,7 +69,50 @@ const resolve = (breakpoints, expr) => { } /** - * Generate a Gemini test suite for the component + * Filter a set of test suites using a regular expression + * + * @param {Array.<object>} components - Component specifications + * @param {Array.<string>} parent - Parent test suite names + * @return {boolean} Whether at least one suite was kept + */ +const filter = (components, parent = []) => { + const regexp = new RegExp(args.grep.replace(" ", ".*?"), "i") + return Object.keys(components).reduce((match, name) => { + const component = components[name] + + /* Deep-copy current path and call recursive */ + const temp = parent.slice(0).concat(name) + const keep = filter(component.suite || {}, temp) + + /* Remove all states that do not match the regular expression */ + component.states = (component.states || [{ name: "", wait: 0 }]).reduce( + (states, state) => { + const fullname = temp.slice(0) + .concat(state.name.length ? [state.name] : []) + .join(" ") + if (regexp.test(fullname)) + states.push(state) + return states + }, []) + + /* Keep komponent, if there is at least one state or the component has + matching subsuites, so it needs to be kept */ + if (component.states.length || keep) { + if (keep) { + delete component.capture + delete component.break + } + return true + } + + /* Otherwise, delete component */ + delete components[name] + return match + }, false) +} + +/** + * Generate Gemini test suites for the given components * * @param {string} dirname - Directory of the test suite * @param {Array.<object>} components - Component specifications // TODO: document syntax and specificagtion @@ -81,11 +132,11 @@ const generate = (dirname, components) => { "_", component.url ? component.url : "")) /* The capture selector is assumed to exist */ - suite.setCaptureElements(component.capture) + if (component.capture) + suite.setCaptureElements(component.capture) /* Generate a subsuite for every state */ - const states = component.states || [{ name: "", wait: 0 }] - for (const state of states) { + for (const state of component.states) { const test = subsuite => { /* Resolve and apply relevant breakpoints */ @@ -129,10 +180,22 @@ const generate = (dirname, components) => { } } +/** + * Register Gemini test suites for the given components + * + * @param {string} dirname - Directory of the test suite + * @param {Array.<object>} components - Component specifications + */ +const register = (dirname, components) => { + if (args.grep) + filter(components) + generate(dirname, components) +} + /* ---------------------------------------------------------------------------- * Exports * ------------------------------------------------------------------------- */ export default { - generate + register } diff --git a/tests/visual/suites/extensions/admonition/suite.js b/tests/visual/suites/extensions/admonition/suite.js index 42b5fd3cb90814ff1230e1cf583b1c13716d355d..7bdbb33c5042192f932486768502a7982b8d8908 100644 --- a/tests/visual/suites/extensions/admonition/suite.js +++ b/tests/visual/suites/extensions/admonition/suite.js @@ -32,7 +32,7 @@ import spec from "~/tests/visual/helpers/spec" * The admonition block looks the same on everything above tablet * portrait, so we can save a few test cases. */ -spec.generate(__dirname, { +spec.register(__dirname, { "admonition": { "url": "/", "capture": "#default + .admonition", diff --git a/tests/visual/suites/layout/nav/suite.js b/tests/visual/suites/layout/nav/suite.js index 29d272aa5fb8e2f6d925bfd0248e6b624882328d..aea23679cef1b64866bc4079429a2c1ef4926a26 100644 --- a/tests/visual/suites/layout/nav/suite.js +++ b/tests/visual/suites/layout/nav/suite.js @@ -41,7 +41,7 @@ const open = () => { /* * Main navigation */ -spec.generate(__dirname, { +spec.register(__dirname, { "md-nav--primary": { "url": "/", "capture": ".md-nav--primary", @@ -84,7 +84,7 @@ spec.generate(__dirname, { /* Last list item */ ":last-child": { "capture": - ".md-nav--primary > .md-nav__list >" + + ".md-nav--primary > .md-nav__list > " + ".md-nav__item:last-child", "break": "+@tablet-landscape", "states": [