|
| 1 | +// @ts-check |
| 2 | +const { source } = require('common-tags') |
| 3 | +const debug = require('debug')('cypress-markdown-preprocessor') |
| 4 | + |
| 5 | +const isTestObject = (o) => o.test |
| 6 | + |
| 7 | +function generateTest(name, maybeTest) { |
| 8 | + if (typeof name !== 'string') { |
| 9 | + console.error(maybeTest) |
| 10 | + throw new Error('Test has no name ' + name) |
| 11 | + } |
| 12 | + |
| 13 | + let itName = 'it' |
| 14 | + if (maybeTest.skip) { |
| 15 | + itName = 'it.skip' |
| 16 | + } else if (maybeTest.only) { |
| 17 | + itName = 'it.only' |
| 18 | + } |
| 19 | + |
| 20 | + return source` |
| 21 | + ${itName}('${name}', () => { |
| 22 | + ${maybeTest.test} |
| 23 | + }) |
| 24 | + ` |
| 25 | +} |
| 26 | + |
| 27 | +/** |
| 28 | + * Processes a tree of test definitions, each with HTML and JS |
| 29 | + * and returns generated spec file source |
| 30 | + */ |
| 31 | +function generateSpecWorker(maybeTest, options) { |
| 32 | + let start = '' |
| 33 | + |
| 34 | + if (options.beforeHooksAtDepth === options.depth) { |
| 35 | + if (options.before) { |
| 36 | + start = |
| 37 | + source` |
| 38 | + before(() => { |
| 39 | + cy.visit('${options.before}') |
| 40 | + }) |
| 41 | + ` + '\n\n' |
| 42 | + } else if (options.beforeEach) { |
| 43 | + start = |
| 44 | + source` |
| 45 | + beforeEach(() => { |
| 46 | + cy.visit('${options.before}') |
| 47 | + }) |
| 48 | + ` + '\n\n' |
| 49 | + } |
| 50 | + } |
| 51 | + |
| 52 | + if (isTestObject(maybeTest)) { |
| 53 | + debug('single test object') |
| 54 | + return start + generateTest(maybeTest.name, maybeTest) |
| 55 | + } |
| 56 | + |
| 57 | + if (Array.isArray(maybeTest)) { |
| 58 | + // console.log('list of tests') |
| 59 | + const sources = maybeTest.map((test) => { |
| 60 | + if (isTestObject(test)) { |
| 61 | + return generateTest(test.name, test) |
| 62 | + } else { |
| 63 | + const nextCallOptions = { |
| 64 | + ...options, |
| 65 | + depth: options.depth + 1, |
| 66 | + } |
| 67 | + return generateSpecWorker(test, nextCallOptions) |
| 68 | + } |
| 69 | + }) |
| 70 | + return start + sources.join('\n\n') |
| 71 | + } |
| 72 | + |
| 73 | + const sources = Object.keys(maybeTest).map((name) => { |
| 74 | + debug('generating test for name "%s"', name) |
| 75 | + const value = maybeTest[name] |
| 76 | + // console.log({ name, value }) |
| 77 | + |
| 78 | + if (isTestObject(value)) { |
| 79 | + // console.log('%s is a test', name) |
| 80 | + |
| 81 | + if (value.skip && value.only) { |
| 82 | + throw new Error(`Test ${name} has both skip and only true`) |
| 83 | + } |
| 84 | + |
| 85 | + return generateTest(name, value) |
| 86 | + } |
| 87 | + |
| 88 | + const nextCallOptions = { |
| 89 | + ...options, |
| 90 | + depth: options.depth + 1, |
| 91 | + } |
| 92 | + |
| 93 | + // final choice - create nested suite of tests |
| 94 | + const inner = generateSpecWorker(value, nextCallOptions) |
| 95 | + return source` |
| 96 | + describe('${name}', () => { |
| 97 | + ${inner} |
| 98 | + }) |
| 99 | + ` |
| 100 | + }) |
| 101 | + |
| 102 | + return start + sources.join('\n') |
| 103 | +} |
| 104 | + |
| 105 | +function generateSpec(maybeTest, options = {}) { |
| 106 | + const opts = { |
| 107 | + ...options, |
| 108 | + depth: 0, |
| 109 | + } |
| 110 | + |
| 111 | + const specSource = generateSpecWorker(maybeTest, opts) |
| 112 | + const preamble = |
| 113 | + source` |
| 114 | + /// <reference types="cypress" /> |
| 115 | + ` + '\n' |
| 116 | + return preamble + specSource |
| 117 | +} |
| 118 | + |
| 119 | +module.exports = { generateSpec } |
0 commit comments