@suffolklitlab/alkiln 3.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/test_tests.yml +77 -0
- package/CHANGELOG.md +381 -0
- package/README.md +18 -0
- package/action.yml +158 -0
- package/lib/DOM.md.html +63 -0
- package/lib/github_integration/install-branch.js +84 -0
- package/lib/github_integration/puppeteer-utils.js +224 -0
- package/lib/github_integration/setup.js +4 -0
- package/lib/github_integration/takedown.js +4 -0
- package/lib/index.js +2 -0
- package/lib/scope.js +1632 -0
- package/lib/steps.js +878 -0
- package/lib/utils/env_vars.js +173 -0
- package/lib/utils/langs.js +51 -0
- package/lib/world.js +10 -0
- package/package.json +53 -0
- package/tests/features/assembly_line.feature +43 -0
- package/tests/features/establishing_steps.feature +22 -0
- package/tests/features/example_test.feature +11 -0
- package/tests/features/interactive_steps.feature +85 -0
- package/tests/features/observation_steps.feature +97 -0
- package/tests/features/reports.feature +482 -0
- package/tests/features/some_png_1.png +0 -0
- package/tests/features/some_png_2.png +0 -0
- package/tests/features/story_table_formats.feature +77 -0
- package/tests/features/story_tables.feature +88 -0
- package/tests/unit_tests/ensureSpecialRows.test.js +34 -0
- package/tests/unit_tests/env_vars.test.js +53 -0
- package/tests/unit_tests/fields.fixtures.js +904 -0
- package/tests/unit_tests/getAllFields.test.js +142 -0
- package/tests/unit_tests/getMatchingRows.test.js +261 -0
- package/tests/unit_tests/getSafeScenarioBaseFilename.fixtures.js +12 -0
- package/tests/unit_tests/getSafeScenarioBaseFilename.test.js +62 -0
- package/tests/unit_tests/getSafeScenarioFilename.test.js +83 -0
- package/tests/unit_tests/html.fixtures.js +861 -0
- package/tests/unit_tests/matches.fixtures.js +168 -0
- package/tests/unit_tests/names.fixtures.js +35 -0
- package/tests/unit_tests/normalizeTable.test.js +22 -0
- package/tests/unit_tests/special_rows.fixtures.js +101 -0
- package/tests/unit_tests/tables.fixtures.js +428 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
|
|
3
|
+
require('dotenv').config();
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This code assumes that this module is run as part of a GitHub Action. If the
|
|
7
|
+
* customer is running it as a CLI tool, then they are on their own.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/* This file provides both `process.env` variables and other variables
|
|
11
|
+
* that are needed in a similar way, but are not `process.env` variables themselves,
|
|
12
|
+
* though they are based on the `process.env` variables.
|
|
13
|
+
*
|
|
14
|
+
* The alternative seems to be some `process.env` type variables and some `foo`
|
|
15
|
+
* variables without great ways to differentiate between them. That or duplicate
|
|
16
|
+
* fiddly work in multiple files.
|
|
17
|
+
*
|
|
18
|
+
* The need to get and set project name, etc. makes me wonder if we should create
|
|
19
|
+
* a class with getters and setters, but general wisdom is that it's a bad idea and
|
|
20
|
+
* maybe it comes to mind because I'm used to asking for `env_vars.CAPS_CASE`. Another
|
|
21
|
+
* alternative is `env_vars.get( 'CAPS_CASE' )` and `env_vars.set( 'CAPS_CASE', 'value' )`
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
// DEBUG is not required.
|
|
25
|
+
|
|
26
|
+
const env_vars = {
|
|
27
|
+
PLAYGROUND_ID: process.env.PLAYGROUND_ID,
|
|
28
|
+
PLAYGROUND_EMAIL: process.env.PLAYGROUND_EMAIL,
|
|
29
|
+
PLAYGROUND_PASSWORD: process.env.PLAYGROUND_PASSWORD,
|
|
30
|
+
BASE_URL: process.env.BASE_URL,
|
|
31
|
+
REPO_URL: process.env.REPO_URL,
|
|
32
|
+
DEBUG: process.env.DEBUG,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* For each field in env_vars, check if the value is defined in an environment
|
|
37
|
+
* variable, and throw an exception if it is not.
|
|
38
|
+
*
|
|
39
|
+
* @throws ReferenceError with a message for all missing variables.
|
|
40
|
+
*/
|
|
41
|
+
env_vars.validateEnvironment = function() {
|
|
42
|
+
|
|
43
|
+
// We are checking for BASE_URL, but we are referring it as SERVER_URL as that
|
|
44
|
+
// is the name used in GitHub secrets, which is what most devs will be using.
|
|
45
|
+
|
|
46
|
+
let errorMessage = '';
|
|
47
|
+
|
|
48
|
+
// Since this code will most often be run in GitHub, I'm going to build a single error message that outlines all missing variables. Otherwise, a developer
|
|
49
|
+
// will have to run their pipeline an incredible number of times to discover all the missing variables.
|
|
50
|
+
if (!process.env.PLAYGROUND_ID)
|
|
51
|
+
{
|
|
52
|
+
errorMessage += '\nThe PLAYGROUND_ID GitHub secret must be defined. The PLAYGROUND_ID is the ID of the Docassemble suite to run.'
|
|
53
|
+
}
|
|
54
|
+
if (!process.env.PLAYGROUND_EMAIL)
|
|
55
|
+
{
|
|
56
|
+
errorMessage += '\nThe PLAYGROUND_EMAIL GitHub secret must be defined. The PLAYGROUND_EMAIL is the e-mail address of the test user to run the Docassemble suite.'
|
|
57
|
+
}
|
|
58
|
+
if (!process.env.PLAYGROUND_PASSWORD)
|
|
59
|
+
{
|
|
60
|
+
errorMessage += '\nThe PLAYGROUND_PASSWORD GitHub secret must be defined. The PLAYGROUND_PASSWORD is your test user\'s password for the test suite.'
|
|
61
|
+
}
|
|
62
|
+
if (!process.env.BASE_URL)
|
|
63
|
+
{
|
|
64
|
+
errorMessage += `\nThe SERVER_URL GitHub secret must be defined. The SERVER_URL is the URL of the Docassemble Server where the tests should be run.`;
|
|
65
|
+
}
|
|
66
|
+
if (!process.env.REPO_URL)
|
|
67
|
+
{
|
|
68
|
+
errorMessage += `\nThe REPO_URL GitHub secret must be defined. The REPO_URL is the URL to the Git repo whose Actions are being run.`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
errorMessage = errorMessage.trim();
|
|
72
|
+
|
|
73
|
+
if (errorMessage !== '')
|
|
74
|
+
throw new ReferenceError(errorMessage);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
env_vars.validateEnvironment();
|
|
78
|
+
|
|
79
|
+
// Path could be 'refs/branch_name' or 'refs/head/branch_name' and maybe other things
|
|
80
|
+
// Assume branch name is last part of branch path
|
|
81
|
+
if ( process.env.BRANCH_PATH ) {
|
|
82
|
+
let split = process.env.BRANCH_PATH.split('/');
|
|
83
|
+
env_vars.BRANCH_NAME = split[ split.length - 1 ];
|
|
84
|
+
} else {
|
|
85
|
+
env_vars.BRANCH_NAME = 'test'
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ---- Project name ----
|
|
89
|
+
let no_starting_digit = ( 'testing' + env_vars.BRANCH_NAME ).replace( /^[0-9]+/i, '' );
|
|
90
|
+
env_vars.PROJECT_BASE_NAME = no_starting_digit.replace( /[^A-Za-z0-9]+/gi, '' );
|
|
91
|
+
|
|
92
|
+
const project_name_file_path = '_al_test_project_name.json';
|
|
93
|
+
env_vars.setProjectName = function ( value ) {
|
|
94
|
+
// As long as it's a string, it can be made safe for a project name
|
|
95
|
+
if ( typeof value !== 'string' ) { throw new TypeError(`The project's name must start as a string. It was ${ value }.`); }
|
|
96
|
+
// Make the name safe for a project name
|
|
97
|
+
let no_starting_digit = value.replace( /^[0-9]+/i, '' );
|
|
98
|
+
let alphanumeric = no_starting_digit.replace( /[^A-Za-z0-9]+/gi, '' );
|
|
99
|
+
// Create or modify a file to store the actual name of the project
|
|
100
|
+
// for later deletion as internal values and context get destroyed before
|
|
101
|
+
// the takedown command that comes later. It's a string, not a list, to avoid
|
|
102
|
+
// the list getting out of date and deleting another test's project.
|
|
103
|
+
fs.writeFileSync( project_name_file_path, JSON.stringify( alphanumeric ));
|
|
104
|
+
console.log( `Saved new project name: ${ alphanumeric }` );
|
|
105
|
+
|
|
106
|
+
return alphanumeric;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
env_vars.getProjectName = function () {
|
|
110
|
+
/* Get the stored name of the project that was created on the
|
|
111
|
+
* server - the base project name might have been adjusted to
|
|
112
|
+
* avoid overwriting existing project. */
|
|
113
|
+
if ( env_vars.DEBUG ) { console.trace( `Getting project name` ); }
|
|
114
|
+
let actual_proj_name = null;
|
|
115
|
+
// Avoid race coditions possibly caused by checking for existence first
|
|
116
|
+
try {
|
|
117
|
+
actual_proj_name = JSON.parse( fs.readFileSync( project_name_file_path ));
|
|
118
|
+
if ( env_vars.DEBUG ) { console.log( `Project name from file is ${ actual_proj_name }.` ); }
|
|
119
|
+
} catch ( error ) {} // Do nothing
|
|
120
|
+
|
|
121
|
+
// If no such file existed or value was invalid, set up the file with a basic name
|
|
122
|
+
if ( !actual_proj_name ) {
|
|
123
|
+
actual_proj_name = env_vars.setProjectName( env_vars.PROJECT_BASE_NAME );
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if ( env_vars.DEBUG ) { console.log( `Processed project name is "${ actual_proj_name }"` ); }
|
|
127
|
+
return actual_proj_name;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
env_vars.cleanUpProjectName = function () {
|
|
131
|
+
/* Delete stored name of project */
|
|
132
|
+
// Avoid race coditions possibly caused by checking for existence first
|
|
133
|
+
// Delete file if possible
|
|
134
|
+
try { fs.unlinkSync( project_name_file_path ); }
|
|
135
|
+
catch ( error ) {
|
|
136
|
+
console.warn(`After trying to delete the project created for the test, the file containing the name of project did not exist. ${ error }`)
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// Notes: We were using `new_session=1` in the url args, but it wasn't
|
|
141
|
+
// always working. The idea was to save each session so we could look
|
|
142
|
+
// back on it if needed. Aside from the fact that you usually need to log in
|
|
143
|
+
// to make the sessions retrievable (though if you're using `interview_list()`
|
|
144
|
+
// you can get them anyway), it also has inconsistent behavior when
|
|
145
|
+
// `sessions are unique`` or `temporary session` or use `interview_list()`
|
|
146
|
+
// and/or respond immediately with a `command()`. Three ways to avoid this:
|
|
147
|
+
// 1. x Start a new browser instead of just a new page each time. Lengthens the tests.
|
|
148
|
+
// 1. √ Visit `/user/sign-out` (needed even if the user is not logged in)
|
|
149
|
+
// 1. x (seems to be causing a 'Unable to locate interview session' error
|
|
150
|
+
// instead) Use `reset=2` instead , which will not save the previous session at all. It
|
|
151
|
+
// Will not just restart any existing interview sessions, it will also
|
|
152
|
+
// clear out the browser session's memory of what other interviews the user has
|
|
153
|
+
// visited in the same browser session.
|
|
154
|
+
env_vars.getBaseInterviewURL = function () {
|
|
155
|
+
/* Return the part of the interview URL that comes before the filename.
|
|
156
|
+
* Depends on the project name, which may have been changed. */
|
|
157
|
+
let new_session = `/interview?new_session=1&i=docassemble.playground`;
|
|
158
|
+
return `${ env_vars.BASE_URL }${ new_session }${ env_vars.PLAYGROUND_ID }${ env_vars.getProjectName() }%3A`;
|
|
159
|
+
};
|
|
160
|
+
env_vars.BASE_INTERVIEW_URL = env_vars.getBaseInterviewURL();
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
// These are actually the words that are on the buttons or links
|
|
164
|
+
// that change the language of the interview. Have not yet detected
|
|
165
|
+
// another distinguishing feature
|
|
166
|
+
if ( process.env.EXTRA_LANGUAGES && process.env.EXTRA_LANGUAGES !== 'default' ) {
|
|
167
|
+
env_vars.EXTRA_LANGUAGES = process.env.EXTRA_LANGUAGES.split(', ');
|
|
168
|
+
} else {
|
|
169
|
+
env_vars.EXTRA_LANGUAGES = [];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
module.exports = env_vars;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
let _path = require('path');
|
|
4
|
+
let fs = require('fs');
|
|
5
|
+
let glob = require('glob');
|
|
6
|
+
|
|
7
|
+
let env_vars = require('./env_vars');
|
|
8
|
+
|
|
9
|
+
// Get the glob filepaths to find all the test files
|
|
10
|
+
let dir_root = process.env.INIT_CWD; // Path to root of project
|
|
11
|
+
let test_glob = process.argv[2]; // String of glob (regex for filepaths)
|
|
12
|
+
let filepaths = glob.sync( _path.resolve( dir_root, test_glob ) );
|
|
13
|
+
let flag = '_lang_';
|
|
14
|
+
|
|
15
|
+
let langs = env_vars.EXTRA_LANGUAGES;
|
|
16
|
+
|
|
17
|
+
// Generate new language files
|
|
18
|
+
for ( let full_path of filepaths ) { // Handle old language files before creating new ones.
|
|
19
|
+
|
|
20
|
+
// Don't apply this to the example test that this package always provides
|
|
21
|
+
if ( full_path.includes( 'example_test.feature' )) { continue; }
|
|
22
|
+
|
|
23
|
+
// Delete alredy existing non-default language files and skip the rest of this. For example,
|
|
24
|
+
// if 3 languages were tested previously and now only two are being tested.
|
|
25
|
+
if ( full_path.includes( flag )) {
|
|
26
|
+
fs.unlinkSync( full_path );
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
for ( let lang of langs ) { // Create new language files
|
|
31
|
+
// Get and change the text from the file to add the language to it
|
|
32
|
+
let data = fs.readFileSync( full_path, 'utf8' );
|
|
33
|
+
let result = data.replace(/(Given I start the interview.*$)/gm, `$1 in lang "${ lang }"`);
|
|
34
|
+
|
|
35
|
+
// Unicode category for NOT language characters \P{L}
|
|
36
|
+
const lang_escaped = lang.replace(/(\P{L})+/gu, '_');
|
|
37
|
+
|
|
38
|
+
// append generated language tags to existing Feature tags if they exist
|
|
39
|
+
const tags_regex = /(?:(?<tags>@.*)\n)?(?=Feature:)/;
|
|
40
|
+
result = result.replace(tags_regex, (_, tags) => `${tags ? tags + ' ' : ''}@generated @lang @${ lang_escaped }\n`);
|
|
41
|
+
|
|
42
|
+
// Save the file to the same folder with a new name indicating the language
|
|
43
|
+
let test_dir = _path.dirname( full_path );
|
|
44
|
+
// Put it alphabetically next to its matching tests by starting with the same name (discuss)
|
|
45
|
+
let orig_filename = _path.basename( full_path ).replace('.feature', '');
|
|
46
|
+
let filename = `${ orig_filename }${ flag }${ lang_escaped }.feature`;
|
|
47
|
+
let fullPath = _path.resolve( test_dir, filename );
|
|
48
|
+
// Always overwrite previous versions of the file if they exist
|
|
49
|
+
fs.writeFileSync(fullPath, result, { encoding:'utf8', flag:'w' });
|
|
50
|
+
}
|
|
51
|
+
}
|
package/lib/world.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@suffolklitlab/alkiln",
|
|
3
|
+
"version": "3.0.9",
|
|
4
|
+
"description": "Integrated automated end-to-end testing with docassemble, puppeteer, and cucumber.",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "npm run unit && npm run langs_setup && npm run cucumber -- $@",
|
|
8
|
+
"cucumber_base": "./node_modules/.bin/cucumber-js --require ./lib/index.js",
|
|
9
|
+
"cucumber": "run_cucumber(){ npm run cucumber_base -- \"$@\" tests/features/*.feature; }; run_cucumber",
|
|
10
|
+
"langs": "npm run langs_setup && ./node_modules/.bin/cucumber-js --require ./lib/index.js tests/features/*_lang*.feature",
|
|
11
|
+
"langs_setup": "./lib/utils/langs.js 'tests/features/*.feature'",
|
|
12
|
+
"langs_local": "npm run langs_setup && npm run local",
|
|
13
|
+
"local": "npm run setup && npm run cucumber; npm run takedown",
|
|
14
|
+
"setup": "./lib/github_integration/setup.js",
|
|
15
|
+
"takedown": "./lib/github_integration/takedown.js",
|
|
16
|
+
"unit": "mocha tests/unit_tests/*.test.*"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/SuffolkLITLab/alkiln.git"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"docassemble",
|
|
24
|
+
"cucumber",
|
|
25
|
+
"puppeteer",
|
|
26
|
+
"automated testing",
|
|
27
|
+
"integrated testing",
|
|
28
|
+
"chai"
|
|
29
|
+
],
|
|
30
|
+
"author": "",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/SuffolkLITLab/alkiln/issues"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://github.com/SuffolkLITLab/alkiln#readme",
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"chai": "^4.2.0",
|
|
38
|
+
"cheerio": "^1.0.0-rc.5",
|
|
39
|
+
"colors": "1.4.0",
|
|
40
|
+
"cucumber": "^6.0.5",
|
|
41
|
+
"dotenv": "^8.2.0",
|
|
42
|
+
"mocha": "^7.2.0",
|
|
43
|
+
"puppeteer": "^3.1.0",
|
|
44
|
+
"sanitize-filename": "^1.6.3",
|
|
45
|
+
"uuid": "^8.3.2"
|
|
46
|
+
},
|
|
47
|
+
"bin": {
|
|
48
|
+
"da-setup": "./lib/github_integration/setup.js",
|
|
49
|
+
"da-takedown": "./lib/github_integration/takedown.js",
|
|
50
|
+
"da-cucumber": "./lib/index.js",
|
|
51
|
+
"da-langs": "./lib/utils/langs.js"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
@assembly_line
|
|
2
|
+
Feature: Assembly Line package-specific Steps
|
|
3
|
+
|
|
4
|
+
# In tag names, 'al' is for 'assembly line'
|
|
5
|
+
|
|
6
|
+
# Note: the first test for this suite is the first test in this file and we're having timeout issues, so we're trying to give the server longer to load.
|
|
7
|
+
|
|
8
|
+
@fast @al1
|
|
9
|
+
Scenario: I have two name parts
|
|
10
|
+
Given the max secs for each step is 120
|
|
11
|
+
Given I start the interview at "AL_tests"
|
|
12
|
+
And I set the name of "users[0]" to "Uli User"
|
|
13
|
+
And I tap to continue
|
|
14
|
+
And I set the address of "users[0]" to "120 Tremont Street, Unit 2, Boston, MA 02108"
|
|
15
|
+
And I tap to continue
|
|
16
|
+
And I set the name of "users[1]" to "Uli2 User2"
|
|
17
|
+
And I set the var "users[i].proxy_var" to "Mixed proxy var step test"
|
|
18
|
+
And I tap to continue
|
|
19
|
+
Then the question id should be "end"
|
|
20
|
+
|
|
21
|
+
@fast @al2
|
|
22
|
+
Scenario: I have three name parts
|
|
23
|
+
Given I start the interview at "AL_tests"
|
|
24
|
+
And I set the name of "users[0]" to "Uli Udo User"
|
|
25
|
+
And I tap to continue
|
|
26
|
+
And I set the address of "users[0]" to "120 Tremont Street, Unit 2, Boston, MA 02108"
|
|
27
|
+
And I tap to continue
|
|
28
|
+
And I set the name of "users[1]" to "Uli2 User2"
|
|
29
|
+
And I set the var "users[i].proxy_var" to "Mixed proxy var step test"
|
|
30
|
+
And I tap to continue
|
|
31
|
+
Then the question id should be "end"
|
|
32
|
+
|
|
33
|
+
@fast @al3
|
|
34
|
+
Scenario: I have four name parts
|
|
35
|
+
Given I start the interview at "AL_tests"
|
|
36
|
+
And I set the name of "users[0]" to "Uli Udo User Sr"
|
|
37
|
+
And I tap to continue
|
|
38
|
+
And I set the address of "users[0]" to "120 Tremont Street, Unit 2, Boston, MA 02108"
|
|
39
|
+
And I tap to continue
|
|
40
|
+
And I set the name of "users[1]" to "Uli2 User2"
|
|
41
|
+
And I set the var "users[i].proxy_var" to "Mixed proxy var step test"
|
|
42
|
+
And I tap to continue
|
|
43
|
+
Then the question id should be "end"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
@establishing
|
|
2
|
+
Feature: Establishing steps
|
|
3
|
+
|
|
4
|
+
Steps that establish things about the state of the test
|
|
5
|
+
# In tag names, 'e' is for 'establishing'
|
|
6
|
+
|
|
7
|
+
@slow @e1
|
|
8
|
+
Scenario: I am able to set a custom wait time that allows steps to run longer than the half minute default
|
|
9
|
+
Given I start the interview at "all_tests"
|
|
10
|
+
And the max seconds for each step in this scenario is 40
|
|
11
|
+
And I wait 35 seconds
|
|
12
|
+
|
|
13
|
+
@slow @e2
|
|
14
|
+
Scenario: I am able to set a custom wait time before an interview has been loaded
|
|
15
|
+
Given the max seconds for each step in this scenario is 40
|
|
16
|
+
And I start the interview at "all_tests"
|
|
17
|
+
And I wait 35 seconds
|
|
18
|
+
|
|
19
|
+
@fast @e3 @urlargs
|
|
20
|
+
Scenario: Interview name includes url args
|
|
21
|
+
Given I start the interview at "url_args.yml&from=theinternets&random=zoo"
|
|
22
|
+
Then I should see the phrase "zoo"
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
@example_feature_tag
|
|
2
|
+
Feature: An example test
|
|
3
|
+
|
|
4
|
+
The tests in this file should cover
|
|
5
|
+
- [x] Provide a template people can use to make their own tests.
|
|
6
|
+
- [ ] Direct people to more documentation.
|
|
7
|
+
- [ ] Find the ultimate question to life, the universe, and everything.
|
|
8
|
+
|
|
9
|
+
@example_scenario_tag
|
|
10
|
+
Scenario: Server finishes reloading
|
|
11
|
+
Given I start the interview at "test"
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
@interactive
|
|
2
|
+
Feature: Interactive steps
|
|
3
|
+
|
|
4
|
+
# In tag names, 'i' is for 'interactive'
|
|
5
|
+
|
|
6
|
+
@slow @i1
|
|
7
|
+
Scenario: I set text-type values
|
|
8
|
+
Given I start the interview at "all_tests"
|
|
9
|
+
Then the question id should be "upload files"
|
|
10
|
+
When I set the var "upload_files_visible" to "some_png_1.png, some_png_2.png"
|
|
11
|
+
And I set the var "show_upload" to "True"
|
|
12
|
+
And I upload "some_png_2.png,some_png_1.png" to "upload_files_hidden"
|
|
13
|
+
And I tap to continue
|
|
14
|
+
# Next page
|
|
15
|
+
Then the question id should be "group of complex fields"
|
|
16
|
+
And I set the var "double_quote_dict['double_quote_key']['dq_two']" to "true"
|
|
17
|
+
And I set the var "single_quote_dict['single_quote_key']['sq_two']" to "true"
|
|
18
|
+
And I tap to continue
|
|
19
|
+
Then the question id should be "direct standard fields"
|
|
20
|
+
# Next page
|
|
21
|
+
When I set the var "checkboxes_yesno" to "True"
|
|
22
|
+
And I set the var "checkboxes_other['checkbox_other_opt_1']" to "true"
|
|
23
|
+
And I set the var "dropdown_test" to "dropdown_opt_2"
|
|
24
|
+
And I set the var "radio_yesno" to "False"
|
|
25
|
+
And I set the var "radio_other" to "radio_other_opt_3"
|
|
26
|
+
And I set the var "text_input" to "Regular text input field value"
|
|
27
|
+
And I set the var "textarea" to "Multiline text\narea value"
|
|
28
|
+
And I set the var "date_input" to "today - 1"
|
|
29
|
+
When I set the var "direct_standard_fields" to "True"
|
|
30
|
+
# Next page
|
|
31
|
+
Then the question id should be "showifs"
|
|
32
|
+
When I set the var "show_2" to "True"
|
|
33
|
+
And I set the var "show_3" to "True"
|
|
34
|
+
And I set the var "showif_checkbox_yesno" to "true"
|
|
35
|
+
And I set the var "showif_checkboxes_other['showif_checkboxes_nota_2']" to "true"
|
|
36
|
+
And I set the var "showif_checkboxes_other['showif_checkboxes_nota_3']" to "true"
|
|
37
|
+
And I set the var "showif_yesnoradio" to "True"
|
|
38
|
+
And I set the var "showif_radio_other" to "showif_radio_multi_2"
|
|
39
|
+
And I set the var "showif_text_input" to "Show if text input value"
|
|
40
|
+
And I set the var "showif_textarea" to "Show if\nmultiline text\narea value"
|
|
41
|
+
And I set the var "showif_dropdown" to "showif_dropdown_1"
|
|
42
|
+
When I tap to continue
|
|
43
|
+
# Next page
|
|
44
|
+
Then the question id should be "buttons yesnomaybe"
|
|
45
|
+
When I set the var "buttons_yesnomaybe" to "None"
|
|
46
|
+
# Next page
|
|
47
|
+
Then the question id should be "buttons other"
|
|
48
|
+
When I set the var "buttons_other" to "button_3"
|
|
49
|
+
# Next page
|
|
50
|
+
Then the question id should be "button continue"
|
|
51
|
+
When I set the var "button_continue" to "True"
|
|
52
|
+
# Next page
|
|
53
|
+
Then the question id should be "screen features"
|
|
54
|
+
When I tap to continue
|
|
55
|
+
# Next page
|
|
56
|
+
Then the question id should be "proxy vars"
|
|
57
|
+
When I set the var "x[i].name.first" to "Proxyname1"
|
|
58
|
+
And I tap to continue
|
|
59
|
+
# Next page
|
|
60
|
+
Then the question id should be "is there another generic"
|
|
61
|
+
When I set the var "x.there_is_another" to "True"
|
|
62
|
+
# Next page
|
|
63
|
+
Then the question id should be "proxy vars"
|
|
64
|
+
When I set the var "x[i].name.first" to "Proxyname2"
|
|
65
|
+
And I tap to continue
|
|
66
|
+
# Next page
|
|
67
|
+
Then the question id should be "is there another generic"
|
|
68
|
+
When I set the var "x.there_is_another" to "False"
|
|
69
|
+
# Next page
|
|
70
|
+
Then the question id should be "first signature"
|
|
71
|
+
When I sign
|
|
72
|
+
And I tap to continue
|
|
73
|
+
# Next page
|
|
74
|
+
Then the question id should be "second signature"
|
|
75
|
+
When I sign
|
|
76
|
+
And I tap to continue
|
|
77
|
+
# Next page
|
|
78
|
+
Then the question id should be "simple doc"
|
|
79
|
+
When I download "simple-doc.pdf"
|
|
80
|
+
And I tap to continue
|
|
81
|
+
# Next page
|
|
82
|
+
Then the question id should be "button event action"
|
|
83
|
+
And I tap to continue
|
|
84
|
+
# Next page
|
|
85
|
+
Then the question id should be "the end"
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
@observation
|
|
2
|
+
Feature: Observational steps
|
|
3
|
+
|
|
4
|
+
# In tag names, 'o' is for 'observational'
|
|
5
|
+
|
|
6
|
+
@fast @o1
|
|
7
|
+
Scenario: I observe things on a single page when I arrive
|
|
8
|
+
Given I start the interview at "all_tests"
|
|
9
|
+
And I tap to continue
|
|
10
|
+
Then the question id should be "group of complex fields"
|
|
11
|
+
And I should see the phrase "Some complex fields"
|
|
12
|
+
And I SHOULD see the phrase "Some complex fields"
|
|
13
|
+
And I should not see the phrase "zzzzzzz"
|
|
14
|
+
And I should NOT see the phrase "zzzzzzz"
|
|
15
|
+
And an element should have the id "daform"
|
|
16
|
+
|
|
17
|
+
@fast @o2
|
|
18
|
+
Scenario: I see user errors.
|
|
19
|
+
# They're everywhere. Some don't even know they are errors.
|
|
20
|
+
Given I start the interview at "all_tests"
|
|
21
|
+
And I tap to continue
|
|
22
|
+
And I tap to continue
|
|
23
|
+
And I tap to continue
|
|
24
|
+
Then I can't continue
|
|
25
|
+
And I will be told an answer is invalid
|
|
26
|
+
|
|
27
|
+
@fast @o3
|
|
28
|
+
Scenario: I can include .yml in the filename
|
|
29
|
+
Given I start the interview at "all_tests.yml"
|
|
30
|
+
|
|
31
|
+
@slow @o4
|
|
32
|
+
Scenario: I check navigation
|
|
33
|
+
Given I start the interview at "all_tests"
|
|
34
|
+
And I tap to continue
|
|
35
|
+
And I get to "showifs" with this data:
|
|
36
|
+
| var | value | trigger |
|
|
37
|
+
| double_quote_dict["double_quote_key"]['dq_two'] | true | |
|
|
38
|
+
| checkboxes_other['checkbox_other_opt_1'] | true | |
|
|
39
|
+
| dropdown_test | dropdown_opt_2 | |
|
|
40
|
+
| radio_yesno | False | false |
|
|
41
|
+
| radio_other | radio_other_opt_3 | |
|
|
42
|
+
| single_quote_dict['single_quote_key']['sq_two'] | true | |
|
|
43
|
+
| text_input | Regular text input field value | |
|
|
44
|
+
| textarea | Multiline text\narea value | |
|
|
45
|
+
| date_input | today | |
|
|
46
|
+
Then I arrive at the next page
|
|
47
|
+
Then I get to "screen features" with this data:
|
|
48
|
+
| var | value | trigger |
|
|
49
|
+
| button_continue | True | |
|
|
50
|
+
| buttons_other | button_2 | |
|
|
51
|
+
| buttons_yesnomaybe | True | |
|
|
52
|
+
And I should see the link to "http://ecosia.org/"
|
|
53
|
+
|
|
54
|
+
@fast @o4
|
|
55
|
+
Scenario: Test "Then I don't continue" with a single quote
|
|
56
|
+
Given I start the interview at "all_tests"
|
|
57
|
+
And I tap to continue
|
|
58
|
+
And I tap to continue
|
|
59
|
+
And I tap to continue
|
|
60
|
+
Then I don't continue
|
|
61
|
+
And I will be told an answer is invalid
|
|
62
|
+
|
|
63
|
+
@fast @o5
|
|
64
|
+
Scenario: Test "Then I cannot continue"
|
|
65
|
+
Given I start the interview at "all_tests"
|
|
66
|
+
And I tap to continue
|
|
67
|
+
And I tap to continue
|
|
68
|
+
And I tap to continue
|
|
69
|
+
Then I cannot continue
|
|
70
|
+
And I will be told an answer is invalid
|
|
71
|
+
|
|
72
|
+
@fast @o6
|
|
73
|
+
Scenario: Test "Then I do not continue"
|
|
74
|
+
Given I start the interview at "all_tests"
|
|
75
|
+
And I tap to continue
|
|
76
|
+
And I tap to continue
|
|
77
|
+
And I tap to continue
|
|
78
|
+
Then I do not continue
|
|
79
|
+
And I will be told an answer is invalid
|
|
80
|
+
|
|
81
|
+
@fast @o7
|
|
82
|
+
Scenario: Test "Then I can’t continue" with an apostrophe
|
|
83
|
+
Given I start the interview at "all_tests"
|
|
84
|
+
And I tap to continue
|
|
85
|
+
And I tap to continue
|
|
86
|
+
And I tap to continue
|
|
87
|
+
Then I can’t continue
|
|
88
|
+
And I will be told an answer is invalid
|
|
89
|
+
|
|
90
|
+
@fast @o8
|
|
91
|
+
Scenario: Test "Then I don’t continue" with an apostrophe
|
|
92
|
+
Given I start the interview at "all_tests"
|
|
93
|
+
And I tap to continue
|
|
94
|
+
And I tap to continue
|
|
95
|
+
And I tap to continue
|
|
96
|
+
Then I don’t continue
|
|
97
|
+
And I will be told an answer is invalid
|