harmonyc 0.1.0 → 0.2.0
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/README.md +85 -0
- package/cli.js +1 -1
- package/compile.js +1 -1
- package/model.js +20 -5
- package/package.json +41 -28
- package/util/xmur3.js +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Harmony Code
|
|
2
|
+
|
|
3
|
+
A simple model-based test design tool that generates Cucumber feature files.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
You need to have Node.js installed. Then you can install Harmony Code in your project folder by:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install harmonyc
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
And then run it for all `.harmony` files in your `src` folder:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
harmonyc src/**/*.harmony
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
This will generate `.feature` files next to the `.harmony` files.
|
|
20
|
+
|
|
21
|
+
## Syntax
|
|
22
|
+
|
|
23
|
+
A `.harmony` file is a text file with a syntax that looks like this:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
Products API:
|
|
27
|
+
+ Create:
|
|
28
|
+
+ Anonymous:
|
|
29
|
+
- create product => error: unauthorized
|
|
30
|
+
+ Admin:
|
|
31
|
+
- authenticate admin
|
|
32
|
+
- create product => product created
|
|
33
|
+
- Delete:
|
|
34
|
+
- delete product => product deleted
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Compiling this with `harmonyc` will generate this `.feature` file:
|
|
38
|
+
|
|
39
|
+
```gherkin
|
|
40
|
+
Feature: products
|
|
41
|
+
|
|
42
|
+
Scenario: T1 - Products API - Create - Anonymous
|
|
43
|
+
When create product -- products
|
|
44
|
+
Then error: unauthorized -- products
|
|
45
|
+
|
|
46
|
+
Scenario: T2 - Products API - Create - Admin - Delete
|
|
47
|
+
When authenticate admin -- products
|
|
48
|
+
When create product -- products
|
|
49
|
+
Then product created -- products
|
|
50
|
+
When delete product -- products
|
|
51
|
+
Then product deleted -- products
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Indentation
|
|
55
|
+
|
|
56
|
+
The lines of a file are nodes of a tree. The tree is specified with the indentation of the lines, which is n times 2 spaces and a `+` or `-` with one more space. The `+` or `-` sign is considered to be part of the indentation.
|
|
57
|
+
|
|
58
|
+
### Sequences and forks
|
|
59
|
+
|
|
60
|
+
`-` means a sequence: the node follows the previous sibling node and its descendants.
|
|
61
|
+
|
|
62
|
+
`+` means a fork: the node directly follows its parent node. All siblings with `+` are separate branches, they will generate separate scenarios.
|
|
63
|
+
|
|
64
|
+
### Labels
|
|
65
|
+
|
|
66
|
+
Label are nodes that end with `:`. You can use them to structure your test design.
|
|
67
|
+
They are not included in the test case, but the test case name is generated from the labels.
|
|
68
|
+
|
|
69
|
+
### Comments
|
|
70
|
+
|
|
71
|
+
Lines starting with `#` or `//` are comments and are ignored.
|
|
72
|
+
|
|
73
|
+
### Steps
|
|
74
|
+
|
|
75
|
+
All other lines are steps. A step consists of an action, and one or more responses denoted by `=>`.
|
|
76
|
+
Actions will become `When` steps, and responses will become `Then` steps.
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
## Running the tests
|
|
80
|
+
|
|
81
|
+
Currenlty `harmonyc` only compiles `.harmony` files to `.feature` files. To run the tests, you need to set up Cucumber or Specflow, depending on your environment.
|
|
82
|
+
|
|
83
|
+
## License
|
|
84
|
+
|
|
85
|
+
MIT
|
package/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
const compiler_1 = require("./compiler");
|
|
5
|
-
if (process.argv.length < 3) {
|
|
5
|
+
if (process.argv.length < 3 || process.argv.includes('--help')) {
|
|
6
6
|
console.error("Usage: harmonyc <input files glob pattern>");
|
|
7
7
|
process.exit(1);
|
|
8
8
|
}
|
package/compile.js
CHANGED
|
@@ -6,7 +6,7 @@ const indent_1 = require("./util/indent");
|
|
|
6
6
|
const model_1 = require("./model");
|
|
7
7
|
const parser_1 = require("./parser");
|
|
8
8
|
function compileFeature(name, src) {
|
|
9
|
-
const root = (0, parser_1.parse)(src);
|
|
9
|
+
const root = (0, parser_1.parse)(src).setFeatureName(name);
|
|
10
10
|
const tests = (0, model_1.makeTests)(root);
|
|
11
11
|
const lines = [
|
|
12
12
|
`Feature: ${name}`,
|
package/model.js
CHANGED
|
@@ -14,6 +14,11 @@ class Branch {
|
|
|
14
14
|
this.isFork = isFork;
|
|
15
15
|
return this;
|
|
16
16
|
}
|
|
17
|
+
setFeatureName(featureName) {
|
|
18
|
+
for (const child of this.children)
|
|
19
|
+
child.setFeatureName(featureName);
|
|
20
|
+
return this;
|
|
21
|
+
}
|
|
17
22
|
addChild(child, index = this.children.length) {
|
|
18
23
|
this.children.splice(index, 0, child);
|
|
19
24
|
child.parent = this;
|
|
@@ -54,10 +59,10 @@ class Branch {
|
|
|
54
59
|
}
|
|
55
60
|
exports.Branch = Branch;
|
|
56
61
|
class Step extends Branch {
|
|
57
|
-
constructor(action = '', responses = [], children, isFork = false) {
|
|
62
|
+
constructor(action = '', responses = [], children, isFork = false, featureName = '') {
|
|
58
63
|
super(children);
|
|
59
|
-
this.action = new Action(action);
|
|
60
|
-
this.responses = responses.map((response) => new Response(response));
|
|
64
|
+
this.action = new Action(action, featureName);
|
|
65
|
+
this.responses = responses.map((response) => new Response(response, featureName));
|
|
61
66
|
this.isFork = isFork;
|
|
62
67
|
}
|
|
63
68
|
get phrases() {
|
|
@@ -66,6 +71,12 @@ class Step extends Branch {
|
|
|
66
71
|
toGherkin() {
|
|
67
72
|
return this.phrases.flatMap((phrase) => phrase.toGherkin());
|
|
68
73
|
}
|
|
74
|
+
setFeatureName(featureName) {
|
|
75
|
+
this.action.setFeatureName(featureName);
|
|
76
|
+
for (const response of this.responses)
|
|
77
|
+
response.setFeatureName(featureName);
|
|
78
|
+
return super.setFeatureName(featureName);
|
|
79
|
+
}
|
|
69
80
|
}
|
|
70
81
|
exports.Step = Step;
|
|
71
82
|
class State {
|
|
@@ -89,11 +100,15 @@ class Section extends Branch {
|
|
|
89
100
|
}
|
|
90
101
|
exports.Section = Section;
|
|
91
102
|
class Phrase {
|
|
92
|
-
constructor(text = '') {
|
|
103
|
+
constructor(text = '', featureName = '') {
|
|
93
104
|
this.text = text;
|
|
105
|
+
this.featureName = featureName;
|
|
106
|
+
}
|
|
107
|
+
setFeatureName(featureName) {
|
|
108
|
+
this.featureName = featureName;
|
|
94
109
|
}
|
|
95
110
|
toGherkin() {
|
|
96
|
-
return [`${this.kind === 'action' ? 'When' : 'Then'} ${this.text}`];
|
|
111
|
+
return [`${this.kind === 'action' ? 'When' : 'Then'} ${this.text} -- ${this.featureName}`];
|
|
97
112
|
}
|
|
98
113
|
}
|
|
99
114
|
exports.Phrase = Phrase;
|
package/package.json
CHANGED
|
@@ -1,28 +1,41 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "harmonyc",
|
|
3
|
-
"description": "Harmony Code - Test design compiler from high-level model to Gherkin",
|
|
4
|
-
"version": "0.
|
|
5
|
-
"author": "Bernát Kalló",
|
|
6
|
-
"bin": {
|
|
7
|
-
"harmonyc": "./cli.js"
|
|
8
|
-
},
|
|
9
|
-
"homepage": "https://github.com/harmony-ac/code#readme",
|
|
10
|
-
"repository": {
|
|
11
|
-
"type": "git",
|
|
12
|
-
"url": "git+https://github.com/harmony-ac/code.git"
|
|
13
|
-
},
|
|
14
|
-
"bugs": {
|
|
15
|
-
"url": "https://github.com/harmony-ac/code/issues"
|
|
16
|
-
},
|
|
17
|
-
"dependencies": {
|
|
18
|
-
"fast-glob": "^3.3.2",
|
|
19
|
-
"typescript-parsec": "0.3.4"
|
|
20
|
-
},
|
|
21
|
-
"license": "MIT",
|
|
22
|
-
"keywords": [
|
|
23
|
-
"unit test",
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "harmonyc",
|
|
3
|
+
"description": "Harmony Code - Test design compiler from high-level model to Gherkin",
|
|
4
|
+
"version": "0.2.0",
|
|
5
|
+
"author": "Bernát Kalló",
|
|
6
|
+
"bin": {
|
|
7
|
+
"harmonyc": "./cli.js"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/harmony-ac/code#readme",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/harmony-ac/code.git"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/harmony-ac/code/issues"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"fast-glob": "^3.3.2",
|
|
19
|
+
"typescript-parsec": "0.3.4"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"keywords": [
|
|
23
|
+
"unit test",
|
|
24
|
+
"unit testing",
|
|
25
|
+
"cucumber",
|
|
26
|
+
"bdd",
|
|
27
|
+
"behavior-driven",
|
|
28
|
+
"test design",
|
|
29
|
+
"test design automation",
|
|
30
|
+
"gherkin",
|
|
31
|
+
"cucumber",
|
|
32
|
+
"specflow",
|
|
33
|
+
"harmony.ac",
|
|
34
|
+
"test framework",
|
|
35
|
+
"model-based test",
|
|
36
|
+
"model-based testing",
|
|
37
|
+
"test model",
|
|
38
|
+
"test modeling",
|
|
39
|
+
"test modelling"
|
|
40
|
+
]
|
|
41
|
+
}
|
package/util/xmur3.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.xmur3 = void 0;
|
|
4
|
-
// https://stackoverflow.com/
|
|
4
|
+
// https://stackoverflow.com/revisions/47593316/25 by bryc (github.com/bryc)
|
|
5
5
|
function xmur3(str) {
|
|
6
6
|
let h = 1779033703 ^ str.length;
|
|
7
7
|
for (let i = 0; i < str.length; i++)
|