@serenity-js/core 3.15.1 → 3.16.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/CHANGELOG.md +22 -0
- package/lib/io/RequirementsHierarchy.d.ts +16 -0
- package/lib/io/RequirementsHierarchy.d.ts.map +1 -0
- package/lib/io/RequirementsHierarchy.js +76 -0
- package/lib/io/RequirementsHierarchy.js.map +1 -0
- package/lib/io/index.d.ts +1 -0
- package/lib/io/index.d.ts.map +1 -1
- package/lib/io/index.js +1 -0
- package/lib/io/index.js.map +1 -1
- package/lib/model/tags/Tag.js +1 -1
- package/lib/model/tags/Tag.js.map +1 -1
- package/lib/screenplay/Actor.d.ts +1 -4
- package/lib/screenplay/Actor.d.ts.map +1 -1
- package/lib/screenplay/Actor.js +1 -4
- package/lib/screenplay/Actor.js.map +1 -1
- package/lib/screenplay/artifacts/CollectsArtifacts.d.ts +54 -0
- package/lib/screenplay/artifacts/CollectsArtifacts.d.ts.map +1 -1
- package/lib/screenplay/questions/Masked.d.ts +35 -0
- package/lib/screenplay/questions/Masked.d.ts.map +1 -0
- package/lib/screenplay/questions/Masked.js +40 -0
- package/lib/screenplay/questions/Masked.js.map +1 -0
- package/lib/screenplay/questions/index.d.ts +1 -0
- package/lib/screenplay/questions/index.d.ts.map +1 -1
- package/lib/screenplay/questions/index.js +1 -0
- package/lib/screenplay/questions/index.js.map +1 -1
- package/lib/screenplay/time/models/Timestamp.d.ts +2 -2
- package/lib/screenplay/time/models/Timestamp.d.ts.map +1 -1
- package/lib/screenplay/time/models/Timestamp.js +39 -14
- package/lib/screenplay/time/models/Timestamp.js.map +1 -1
- package/package.json +2 -3
- package/src/io/RequirementsHierarchy.ts +87 -0
- package/src/io/index.ts +1 -0
- package/src/model/tags/Tag.ts +1 -1
- package/src/screenplay/Actor.ts +1 -4
- package/src/screenplay/artifacts/CollectsArtifacts.ts +54 -0
- package/src/screenplay/questions/Masked.ts +38 -0
- package/src/screenplay/questions/index.ts +1 -0
- package/src/screenplay/time/models/Timestamp.ts +45 -12
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,28 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [3.16.0](https://github.com/serenity-js/serenity-js/compare/v3.15.1...v3.16.0) (2024-02-01)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **core:** introduced RequirementsHierarchy to centralise requirements detection logic ([0a3d6f0](https://github.com/serenity-js/serenity-js/commit/0a3d6f013a3b94ca471edc263e1157b7c41131be))
|
|
12
|
+
* **core:** recognise `specs` as a potential requirements hierarchy root ([d95d850](https://github.com/serenity-js/serenity-js/commit/d95d85058fd5e4e01aec689b7196989ece5e303f))
|
|
13
|
+
* **core:** removed dependency on Moment.js ([edd1d64](https://github.com/serenity-js/serenity-js/commit/edd1d64f30893983b92bd600d102c81577c0ecb1))
|
|
14
|
+
* **core:** simplified the Timestampt validation regex and improved error messages ([b453a23](https://github.com/serenity-js/serenity-js/commit/b453a23de419dbd811927b9447c17678e39f8cc8))
|
|
15
|
+
* **core:** support for timezones and simplified date time strings when creating Timestamps ([754f8e2](https://github.com/serenity-js/serenity-js/commit/754f8e260d2fc5130075a78ec58084eafcf2c83f))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* **core:** added Masked.valueOf() Question ([e9ff5ab](https://github.com/serenity-js/serenity-js/commit/e9ff5ab62e8b305aa7ef2238f482be5369d890c1)), closes [#2165](https://github.com/serenity-js/serenity-js/issues/2165)
|
|
21
|
+
* **mocha:** support for nested requirements reporting ([f8e70ce](https://github.com/serenity-js/serenity-js/commit/f8e70ce8a317ab6e8bdf4d058110f110b4c8deda))
|
|
22
|
+
* **serenity-bdd:** upgraded Serenity BDD to 4.0.44 ([4e2f1e3](https://github.com/serenity-js/serenity-js/commit/4e2f1e3b273712c44a7f749ba9570f121520cdd5))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
6
28
|
## [3.15.1](https://github.com/serenity-js/serenity-js/compare/v3.15.0...v3.15.1) (2024-01-19)
|
|
7
29
|
|
|
8
30
|
**Note:** Version bump only for package @serenity-js/core
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Tag } from '../model';
|
|
2
|
+
import type { FileSystem } from './FileSystem';
|
|
3
|
+
import { Path } from './Path';
|
|
4
|
+
export declare class RequirementsHierarchy {
|
|
5
|
+
private readonly fileSystem;
|
|
6
|
+
private readonly userDefinedSpecDirectory?;
|
|
7
|
+
private root;
|
|
8
|
+
private static readonly specDirectoryCandidates;
|
|
9
|
+
constructor(fileSystem: FileSystem, userDefinedSpecDirectory?: Path);
|
|
10
|
+
requirementTagsFor(pathToSpec: Path, featureName?: string): Tag[];
|
|
11
|
+
hierarchyFor(pathToSpec: Path): string[];
|
|
12
|
+
rootDirectory(): Path;
|
|
13
|
+
private guessRootDirectory;
|
|
14
|
+
private resolve;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=RequirementsHierarchy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RequirementsHierarchy.d.ts","sourceRoot":"","sources":["../../src/io/RequirementsHierarchy.ts"],"names":[],"mappings":"AACA,OAAO,EAA6B,GAAG,EAAY,MAAM,UAAU,CAAC;AACpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B,qBAAa,qBAAqB;IAc1B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IAb9C,OAAO,CAAC,IAAI,CAAO;IAEnB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAO7C;gBAGmB,UAAU,EAAE,UAAU,EACtB,wBAAwB,CAAC,EAAE,IAAI;IAIpD,kBAAkB,CAAC,UAAU,EAAE,IAAI,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,GAAG,EAAE;IAgBjE,YAAY,CAAC,UAAU,EAAE,IAAI,GAAG,MAAM,EAAE;IAiBxC,aAAa,IAAI,IAAI;IAUrB,OAAO,CAAC,kBAAkB;IAY1B,OAAO,CAAC,OAAO;CAOlB"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RequirementsHierarchy = void 0;
|
|
4
|
+
const errors_1 = require("../errors");
|
|
5
|
+
const model_1 = require("../model");
|
|
6
|
+
const Path_1 = require("./Path");
|
|
7
|
+
class RequirementsHierarchy {
|
|
8
|
+
fileSystem;
|
|
9
|
+
userDefinedSpecDirectory;
|
|
10
|
+
root;
|
|
11
|
+
static specDirectoryCandidates = [
|
|
12
|
+
`features`,
|
|
13
|
+
`specs`,
|
|
14
|
+
`spec`,
|
|
15
|
+
`tests`,
|
|
16
|
+
`test`,
|
|
17
|
+
`src`,
|
|
18
|
+
];
|
|
19
|
+
constructor(fileSystem, userDefinedSpecDirectory) {
|
|
20
|
+
this.fileSystem = fileSystem;
|
|
21
|
+
this.userDefinedSpecDirectory = userDefinedSpecDirectory;
|
|
22
|
+
}
|
|
23
|
+
requirementTagsFor(pathToSpec, featureName) {
|
|
24
|
+
const [fileBasedFeatureName, capabilityName, ...themeNames] = this.hierarchyFor(pathToSpec).reverse().filter(segment => !['.', '..'].includes(segment));
|
|
25
|
+
const themeTags = themeNames.reverse().map(themeName => model_1.Tag.humanReadable(model_1.ThemeTag, themeName));
|
|
26
|
+
const capabilityTag = capabilityName && model_1.Tag.humanReadable(model_1.CapabilityTag, capabilityName);
|
|
27
|
+
const featureTag = featureName
|
|
28
|
+
? new model_1.FeatureTag(featureName)
|
|
29
|
+
: model_1.Tag.humanReadable(model_1.FeatureTag, fileBasedFeatureName);
|
|
30
|
+
return [
|
|
31
|
+
...themeTags,
|
|
32
|
+
capabilityTag,
|
|
33
|
+
featureTag
|
|
34
|
+
].filter(Boolean);
|
|
35
|
+
}
|
|
36
|
+
hierarchyFor(pathToSpec) {
|
|
37
|
+
const relative = this.rootDirectory().relative(pathToSpec);
|
|
38
|
+
return relative.split().map((segment, i, segments) => {
|
|
39
|
+
// return all the segments as-is, except for the last one
|
|
40
|
+
if (i < segments.length - 1) {
|
|
41
|
+
return segment;
|
|
42
|
+
}
|
|
43
|
+
// Strip the extension, like `.feature` or `.spec.ts`
|
|
44
|
+
const firstDotIndex = segment.indexOf('.');
|
|
45
|
+
return firstDotIndex === -1
|
|
46
|
+
? segment
|
|
47
|
+
: segment.slice(0, firstDotIndex);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
rootDirectory() {
|
|
51
|
+
if (!this.root) {
|
|
52
|
+
this.root = this.userDefinedSpecDirectory
|
|
53
|
+
? this.resolve(this.userDefinedSpecDirectory)
|
|
54
|
+
: this.guessRootDirectory();
|
|
55
|
+
}
|
|
56
|
+
return this.root;
|
|
57
|
+
}
|
|
58
|
+
guessRootDirectory() {
|
|
59
|
+
for (const candidate of RequirementsHierarchy.specDirectoryCandidates) {
|
|
60
|
+
const candidateSpecDirectory = Path_1.Path.from(candidate);
|
|
61
|
+
if (this.fileSystem.exists(Path_1.Path.from(candidate))) {
|
|
62
|
+
return this.fileSystem.resolve(candidateSpecDirectory);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// default to current working directory
|
|
66
|
+
return this.fileSystem.resolve(Path_1.Path.from('.'));
|
|
67
|
+
}
|
|
68
|
+
resolve(userDefinedRootDirectory) {
|
|
69
|
+
if (!this.fileSystem.exists(userDefinedRootDirectory)) {
|
|
70
|
+
throw new errors_1.ConfigurationError(`Configured specDirectory \`${userDefinedRootDirectory}\` does not exist`);
|
|
71
|
+
}
|
|
72
|
+
return this.fileSystem.resolve(userDefinedRootDirectory);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
exports.RequirementsHierarchy = RequirementsHierarchy;
|
|
76
|
+
//# sourceMappingURL=RequirementsHierarchy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RequirementsHierarchy.js","sourceRoot":"","sources":["../../src/io/RequirementsHierarchy.ts"],"names":[],"mappings":"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"}
|
package/lib/io/index.d.ts
CHANGED
package/lib/io/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/io/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/io/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,yBAAyB,CAAC;AACxC,cAAc,WAAW,CAAC"}
|
package/lib/io/index.js
CHANGED
|
@@ -26,5 +26,6 @@ __exportStar(require("./inspectedObject"), exports);
|
|
|
26
26
|
__exportStar(require("./loader"), exports);
|
|
27
27
|
__exportStar(require("./Path"), exports);
|
|
28
28
|
__exportStar(require("./reflection"), exports);
|
|
29
|
+
__exportStar(require("./RequirementsHierarchy"), exports);
|
|
29
30
|
__exportStar(require("./trimmed"), exports);
|
|
30
31
|
//# sourceMappingURL=index.js.map
|
package/lib/io/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/io/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA2B;AAC3B,mDAAiC;AACjC,2CAAyB;AACzB,+CAA6B;AAC7B,+CAA6B;AAC7B,uDAAqC;AACrC,2CAAyB;AACzB,8CAA4B;AAC5B,oDAAkC;AAClC,2CAAyB;AACzB,yCAAuB;AACvB,+CAA6B;AAC7B,4CAA0B"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/io/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA2B;AAC3B,mDAAiC;AACjC,2CAAyB;AACzB,+CAA6B;AAC7B,+CAA6B;AAC7B,uDAAqC;AACrC,2CAAyB;AACzB,8CAA4B;AAC5B,oDAAkC;AAClC,2CAAyB;AACzB,yCAAuB;AACvB,+CAA6B;AAC7B,0DAAwC;AACxC,4CAA0B"}
|
package/lib/model/tags/Tag.js
CHANGED
|
@@ -36,7 +36,7 @@ class Tag extends tiny_types_1.TinyType {
|
|
|
36
36
|
// based on https://github.com/serenity-bdd/serenity-core/blob/8f7d14c6dad47bb58a1585fef5f9d9a44bb963fd/serenity-model/src/main/java/net/thucydides/core/requirements/AbstractRequirementsTagProvider.java#L36
|
|
37
37
|
const name = String(tagName)
|
|
38
38
|
.trim()
|
|
39
|
-
.match(/[\dA-Z]{2,}(?=[A-Z][a-z]+\d*|\b)|[A-Z]?[a-z]+\d*|[A-Z]|\d+/g)
|
|
39
|
+
.match(/[\dA-Z]{2,}(?=[A-Z][a-z]+\d*|\b)|[A-Z]?[a-z-]+\d*|[A-Z]|\d+/g)
|
|
40
40
|
.map(chunk => /^[A-Z]+$/.test(chunk) ? chunk : chunk.toLowerCase())
|
|
41
41
|
.join('_')
|
|
42
42
|
.replaceAll(/[\s_]+/g, ' ');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tag.js","sourceRoot":"","sources":["../../../src/model/tags/Tag.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AACA,2CAA4F;AAE5F,kDAAoC;AAEpC;;GAEG;AACH,MAAsB,GAAI,SAAQ,qBAAQ;IA0BA;IAA8B;IAzBpE,MAAM,CAAC,aAAa,CAAC,cAAyC,EAAE,OAAe;QAC3E,8MAA8M;QAC9M,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC;aACvB,IAAI,EAAE;aACN,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"Tag.js","sourceRoot":"","sources":["../../../src/model/tags/Tag.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AACA,2CAA4F;AAE5F,kDAAoC;AAEpC;;GAEG;AACH,MAAsB,GAAI,SAAQ,qBAAQ;IA0BA;IAA8B;IAzBpE,MAAM,CAAC,aAAa,CAAC,cAAyC,EAAE,OAAe;QAC3E,8MAA8M;QAC9M,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC;aACvB,IAAI,EAAE;aACN,KAAK,CAAC,8DAA8D,CAAC;aACrE,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;aAClE,IAAI,CAAC,GAAG,CAAC;aACT,UAAU,CAAC,SAAS,EAAE,GAAG,CAAC,CAC9B;QAED,OAAO,IAAI,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5E,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,CAAa;QACzB,MAAM,IAAI,GAAW,IAAA,mBAAM,EAAC,qBAAqB,EAAE,CAAC,CAAC,IAAI,EAAE,IAAA,sBAAS,GAAE,EAAE,IAAA,qBAAQ,GAAE,CAAW,CAAC;QAE9F,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC;QAEvG,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,EAAE;YACnE,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;SACtC;QAED,OAAO,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC;IAED,YAAsC,IAAY,EAAkB,IAAY;QAC5E,KAAK,EAAE,CAAC;QAD0B,SAAI,GAAJ,IAAI,CAAQ;QAAkB,SAAI,GAAJ,IAAI,CAAQ;QAG5E,IAAA,mBAAM,EAAC,UAAU,EAAE,IAAI,EAAE,IAAA,sBAAS,GAAE,EAAE,IAAA,qBAAQ,EAAC,QAAQ,EAAE,IAAA,0BAAa,EAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5E,IAAA,mBAAM,EAAC,UAAU,EAAE,IAAI,EAAE,IAAA,sBAAS,GAAE,EAAE,IAAA,qBAAQ,EAAC,QAAQ,EAAE,IAAA,0BAAa,EAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAChF,CAAC;IAED,MAAM;QACF,OAAO,KAAK,CAAC,MAAM,EAAoC,CAAC;IAC5D,CAAC;CACJ;AApCD,kBAoCC"}
|
|
@@ -116,10 +116,7 @@ export declare class Actor implements PerformsActivities, UsesAbilities, CanHave
|
|
|
116
116
|
*/
|
|
117
117
|
answer<T>(answerable: Answerable<T>): Promise<T>;
|
|
118
118
|
/**
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
* @param artifact
|
|
122
|
-
* @param name
|
|
119
|
+
* @inheritDoc
|
|
123
120
|
*/
|
|
124
121
|
collect(artifact: Artifact, name?: string | Name): void;
|
|
125
122
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Actor.d.ts","sourceRoot":"","sources":["../../src/screenplay/Actor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAC,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,IAAI,EAAG,MAAM,UAAU,CAAC;AACjC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,KAAK,EACR,WAAW,EACX,gBAAgB,EAGhB,aAAa,EAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EACH,OAAO,EAGV,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,qBAAa,KAAM,YAAW,kBAAkB,EAC5C,aAAa,EACb,gBAAgB,CAAC,KAAK,CAAC,EACvB,gBAAgB,EAChB,iBAAiB,EACjB,SAAS;aAKW,IAAI,EAAE,MAAM;IAC5B,OAAO,CAAC,QAAQ,CAAC,KAAK;IAJ1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgF;gBAGtF,IAAI,EAAE,MAAM,EACX,KAAK,EAAE,KAAK,EAC7B,SAAS,GAAE,OAAO,EAAO;IAS7B;;;;;;;;;;OAUG;IACH,SAAS,CAAC,CAAC,SAAS,OAAO,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC;IAc5D;;;;;;OAMG;IACH,UAAU,CAAC,GAAG,UAAU,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAQpD;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,GAAG,SAAS,EAAE,OAAO,EAAE,GAAG,KAAK;IAMtC;;;;;;OAMG;IACH,MAAM,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAIhD
|
|
1
|
+
{"version":3,"file":"Actor.d.ts","sourceRoot":"","sources":["../../src/screenplay/Actor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAC,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,IAAI,EAAG,MAAM,UAAU,CAAC;AACjC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,KAAK,EACR,WAAW,EACX,gBAAgB,EAGhB,aAAa,EAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EACH,OAAO,EAGV,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,qBAAa,KAAM,YAAW,kBAAkB,EAC5C,aAAa,EACb,gBAAgB,CAAC,KAAK,CAAC,EACvB,gBAAgB,EAChB,iBAAiB,EACjB,SAAS;aAKW,IAAI,EAAE,MAAM;IAC5B,OAAO,CAAC,QAAQ,CAAC,KAAK;IAJ1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgF;gBAGtF,IAAI,EAAE,MAAM,EACX,KAAK,EAAE,KAAK,EAC7B,SAAS,GAAE,OAAO,EAAO;IAS7B;;;;;;;;;;OAUG;IACH,SAAS,CAAC,CAAC,SAAS,OAAO,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC;IAc5D;;;;;;OAMG;IACH,UAAU,CAAC,GAAG,UAAU,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAQpD;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,GAAG,SAAS,EAAE,OAAO,EAAE,GAAG,KAAK;IAMtC;;;;;;OAMG;IACH,MAAM,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAIhD;;OAEG;IACH,OAAO,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAUvD;;OAEG;IACH,WAAW,IAAI,SAAS;IAIxB;;;OAGG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IASxB;;;;OAIG;IACH,QAAQ,IAAI,MAAM;IAMlB,OAAO,CAAC,mBAAmB;IAc3B,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,iBAAiB;IASzB;;;;;OAKG;IACH,OAAO,CAAC,QAAQ;CAKnB"}
|
package/lib/screenplay/Actor.js
CHANGED
|
@@ -140,10 +140,7 @@ class Actor {
|
|
|
140
140
|
return abilities_1.AnswerQuestions.as(this).answer(answerable);
|
|
141
141
|
}
|
|
142
142
|
/**
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
* @param artifact
|
|
146
|
-
* @param name
|
|
143
|
+
* @inheritDoc
|
|
147
144
|
*/
|
|
148
145
|
collect(artifact, name) {
|
|
149
146
|
this.stage.announce(new events_1.ActivityRelatedArtifactGenerated(this.stage.currentSceneId(), this.stage.currentActivityId(), this.nameFrom(name || new model_1.Name(artifact.constructor.name)), artifact, this.stage.currentTime()));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Actor.js","sourceRoot":"","sources":["../../src/screenplay/Actor.ts"],"names":[],"mappings":";;;AAAA,sCAAqE;AACrE,sCAA6D;AAC7D,8BAA+B;AAE/B,oCAAiC;AASjC,2CAIqB;AAQrB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,MAAa,KAAK;IAUM;IACC;IAJJ,SAAS,GAAuC,IAAI,GAAG,EAAiC,CAAC;IAE1G,YACoB,IAAY,EACX,KAAY,EAC7B,YAAuB,EAAE;QAFT,SAAI,GAAJ,IAAI,CAAQ;QACX,UAAK,GAAL,KAAK,CAAO;QAG7B;YACI,IAAI,6BAAiB,CAAC,IAAI,EAAE,KAAK,CAAC;YAClC,IAAI,2BAAe,CAAC,IAAI,CAAC;YACzB,GAAG,SAAS;SACf,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IACvD,CAAC;IAED;;;;;;;;;;OAUG;IACH,SAAS,CAAoB,WAA2B;QACpD,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;QAE9C,IAAI,CAAE,KAAK,EAAE;YACT,MAAM,IAAI,2BAAkB,CACxB,GAAI,IAAI,CAAC,IAAK,QAAS,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAE,IAAI;gBAC/F,wBAAyB,WAAW,CAAC,IAAK,QAAQ;gBAClD,yCAAyC,CAC5C,CAAC;SACL;QAED,OAAO,KAAK,CAAC;IACjB,CAAC;IAED;;;;;;OAMG;IACH,UAAU,CAAC,GAAG,UAAsB;QAChC,OAAO,UAAU;aACZ,MAAM,CAAC,CAAC,QAAuB,EAAE,OAAiB,EAAE,EAAE;YACnD,OAAO,QAAQ;iBACV,IAAI,CAAC,GAAG,EAAE,CAAC,6BAAiB,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;QACjE,CAAC,EAAE,IAAI,CAAC,mBAAmB,EAAE,CAAC,CAAC;IACvC,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,GAAG,SAAoB;QAC1B,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;QAE3D,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAI,UAAyB;QAC/B,OAAO,2BAAe,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACvD,CAAC;IAED
|
|
1
|
+
{"version":3,"file":"Actor.js","sourceRoot":"","sources":["../../src/screenplay/Actor.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,6 +13,60 @@ export interface CollectsArtifacts {
|
|
|
13
13
|
/**
|
|
14
14
|
* Makes the {@apilink Actor} collect an {@apilink Artifact} so that it can be included in the test report.
|
|
15
15
|
*
|
|
16
|
+
* #### Implementing a custom interaction to attach artifacts
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* import * as fs from 'node:fs'
|
|
20
|
+
* import { Answerable, Interaction } from '@serenity-js/core'
|
|
21
|
+
* import { Path } from '@serenity-js/core/lib/io'
|
|
22
|
+
* import { Name, TextData } from '@serenity-js/core/lib/model'
|
|
23
|
+
*
|
|
24
|
+
* export class Attach {
|
|
25
|
+
*
|
|
26
|
+
* static contentsOf = (pathToFile: Path): Interaction =>
|
|
27
|
+
* Interaction.where(`#actor attaches contents of ${ pathToFile.basename() }`, async actor => {
|
|
28
|
+
* const data = fs.readFileSync(pathToFile.value).toString('utf-8');
|
|
29
|
+
*
|
|
30
|
+
* actor.collect(
|
|
31
|
+
* TextData.fromJSON({ contentType: 'text/plain', data }),
|
|
32
|
+
* new Name(pathToFile.basename()),
|
|
33
|
+
* )
|
|
34
|
+
* })
|
|
35
|
+
*
|
|
36
|
+
* static textData = (contents: Answerable<string>, name?: string): Interaction =>
|
|
37
|
+
* Interaction.where(`#actor attaches text data`, async actor => {
|
|
38
|
+
* const data = await actor.answer(contents);
|
|
39
|
+
*
|
|
40
|
+
* actor.collect(
|
|
41
|
+
* TextData.fromJSON({ contentType: 'text/plain', data }),
|
|
42
|
+
* name && new Name(name),
|
|
43
|
+
* )
|
|
44
|
+
* })
|
|
45
|
+
* }
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* #### Attaching plain text
|
|
49
|
+
*
|
|
50
|
+
* ```ts
|
|
51
|
+
* import { actorCalled } from '@serenity-js/core'
|
|
52
|
+
* import { Path } from '@serenity-js/core/lib/io'
|
|
53
|
+
*
|
|
54
|
+
* actorCalled('Alice').attemptsTo(
|
|
55
|
+
* Attach.textData('some text', 'some name'),
|
|
56
|
+
* )
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* #### Attaching contents of a text file
|
|
60
|
+
*
|
|
61
|
+
* ```ts
|
|
62
|
+
* import { actorCalled } from '@serenity-js/core'
|
|
63
|
+
* import { Log } from '@serenity-js/core'
|
|
64
|
+
*
|
|
65
|
+
* actorCalled('Alice').attemptsTo(
|
|
66
|
+
* Attach.contentsOf(Path.from(__dirname, 'output/server.log')),
|
|
67
|
+
* )
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
16
70
|
* @param artifact
|
|
17
71
|
* The artifact to be collected, such as {@apilink JSONData}
|
|
18
72
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollectsArtifacts.d.ts","sourceRoot":"","sources":["../../../src/screenplay/artifacts/CollectsArtifacts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;;;;GASG;AACH,MAAM,WAAW,iBAAiB;IAE9B
|
|
1
|
+
{"version":3,"file":"CollectsArtifacts.d.ts","sourceRoot":"","sources":["../../../src/screenplay/artifacts/CollectsArtifacts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;;;;GASG;AACH,MAAM,WAAW,iBAAiB;IAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8DG;IACH,OAAO,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CAClD"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { QuestionAdapter } from '..';
|
|
2
|
+
import { type Answerable } from '..';
|
|
3
|
+
/**
|
|
4
|
+
* This question masks sensitive data handled by the actors and prevents
|
|
5
|
+
* it from being shown in Serenity/JS reports and console logs.
|
|
6
|
+
* You should use it to wrap passwords, secret tokens, phone numbers,
|
|
7
|
+
* credit card numbers, or any other personally identifiable information (PII).
|
|
8
|
+
* However, even though the wrapped value is masked in the output,
|
|
9
|
+
* you can still retrieve the unmasked value by making the actor answer
|
|
10
|
+
* the question in your custom interactions.
|
|
11
|
+
*
|
|
12
|
+
* @group Questions
|
|
13
|
+
*/
|
|
14
|
+
export declare class Masked {
|
|
15
|
+
/**
|
|
16
|
+
* Retrieves the value of a sensitive parameter and mask it in any report.
|
|
17
|
+
*
|
|
18
|
+
* #### Example
|
|
19
|
+
*
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { actorCalled, Masked } from '@serenity-js/core';
|
|
22
|
+
* import { Ensure, equals } from '@serenity-js/assertions';
|
|
23
|
+
*
|
|
24
|
+
* await actorCalled('John')
|
|
25
|
+
* .attemptsTo(
|
|
26
|
+
* Enter.theValue(Masked.valueOf('your little secret').into(Form.exampleInput())
|
|
27
|
+
* );
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @param parameter - An {@link Answerable} representing the masked value.
|
|
31
|
+
* @returns A {@link QuestionAdapter} representing the masked value.
|
|
32
|
+
*/
|
|
33
|
+
static valueOf(parameter: Answerable<string>): QuestionAdapter<string>;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=Masked.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Masked.d.ts","sourceRoot":"","sources":["../../../src/screenplay/questions/Masked.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAC1C,OAAO,EAAE,KAAK,UAAU,EAAW,MAAM,IAAI,CAAC;AAE9C;;;;;;;;;;GAUG;AACH,qBAAa,MAAM;IAEf;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,UAAU,CAAC,MAAM,CAAC,GAAK,eAAe,CAAC,MAAM,CAAC;CAG3E"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Masked = void 0;
|
|
4
|
+
const __1 = require("..");
|
|
5
|
+
/**
|
|
6
|
+
* This question masks sensitive data handled by the actors and prevents
|
|
7
|
+
* it from being shown in Serenity/JS reports and console logs.
|
|
8
|
+
* You should use it to wrap passwords, secret tokens, phone numbers,
|
|
9
|
+
* credit card numbers, or any other personally identifiable information (PII).
|
|
10
|
+
* However, even though the wrapped value is masked in the output,
|
|
11
|
+
* you can still retrieve the unmasked value by making the actor answer
|
|
12
|
+
* the question in your custom interactions.
|
|
13
|
+
*
|
|
14
|
+
* @group Questions
|
|
15
|
+
*/
|
|
16
|
+
class Masked {
|
|
17
|
+
/**
|
|
18
|
+
* Retrieves the value of a sensitive parameter and mask it in any report.
|
|
19
|
+
*
|
|
20
|
+
* #### Example
|
|
21
|
+
*
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { actorCalled, Masked } from '@serenity-js/core';
|
|
24
|
+
* import { Ensure, equals } from '@serenity-js/assertions';
|
|
25
|
+
*
|
|
26
|
+
* await actorCalled('John')
|
|
27
|
+
* .attemptsTo(
|
|
28
|
+
* Enter.theValue(Masked.valueOf('your little secret').into(Form.exampleInput())
|
|
29
|
+
* );
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @param parameter - An {@link Answerable} representing the masked value.
|
|
33
|
+
* @returns A {@link QuestionAdapter} representing the masked value.
|
|
34
|
+
*/
|
|
35
|
+
static valueOf(parameter) {
|
|
36
|
+
return __1.Question.about('[a masked value]', async (actor) => actor.answer(parameter));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.Masked = Masked;
|
|
40
|
+
//# sourceMappingURL=Masked.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Masked.js","sourceRoot":"","sources":["../../../src/screenplay/questions/Masked.ts"],"names":[],"mappings":";;;AACA,0BAA8C;AAE9C;;;;;;;;;;GAUG;AACH,MAAa,MAAM;IAEf;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,OAAO,CAAC,SAA6B;QACxC,OAAO,YAAQ,CAAC,KAAK,CAAC,kBAAkB,EAAE,KAAK,EAAC,KAAK,EAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAA;IACrF,CAAC;CACJ;AAvBD,wBAuBC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screenplay/questions/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,KAAK,CAAC;AACpB,cAAc,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screenplay/questions/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,KAAK,CAAC;AACpB,cAAc,cAAc,CAAC"}
|
|
@@ -20,6 +20,7 @@ __exportStar(require("./Check"), exports);
|
|
|
20
20
|
__exportStar(require("./Expectation"), exports);
|
|
21
21
|
__exportStar(require("./expectations"), exports);
|
|
22
22
|
__exportStar(require("./List"), exports);
|
|
23
|
+
__exportStar(require("./Masked"), exports);
|
|
23
24
|
__exportStar(require("./MetaQuestion"), exports);
|
|
24
25
|
__exportStar(require("./q"), exports);
|
|
25
26
|
__exportStar(require("./Unanswered"), exports);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/screenplay/questions/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,qDAAmC;AACnC,0DAAwC;AACxC,0CAAwB;AACxB,gDAA8B;AAC9B,iDAA+B;AAC/B,yCAAuB;AACvB,iDAA+B;AAC/B,sCAAoB;AACpB,+CAA6B"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/screenplay/questions/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,qDAAmC;AACnC,0DAAwC;AACxC,0CAAwB;AACxB,gDAA8B;AAC9B,iDAA+B;AAC/B,yCAAuB;AACvB,2CAAyB;AACzB,iDAA+B;AAC/B,sCAAoB;AACpB,+CAA6B"}
|
|
@@ -16,8 +16,8 @@ import { Duration } from './Duration';
|
|
|
16
16
|
export declare class Timestamp extends TinyType {
|
|
17
17
|
readonly value: Date;
|
|
18
18
|
static fromJSON(v: string): Timestamp;
|
|
19
|
-
static fromTimestampInSeconds(
|
|
20
|
-
static fromTimestampInMilliseconds(
|
|
19
|
+
static fromTimestampInSeconds(value: number): Timestamp;
|
|
20
|
+
static fromTimestampInMilliseconds(value: number): Timestamp;
|
|
21
21
|
static now(): Timestamp;
|
|
22
22
|
constructor(value?: Date);
|
|
23
23
|
diff(another: Timestamp): Duration;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Timestamp.d.ts","sourceRoot":"","sources":["../../../../src/screenplay/time/models/Timestamp.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"Timestamp.d.ts","sourceRoot":"","sources":["../../../../src/screenplay/time/models/Timestamp.ts"],"names":[],"mappings":";AAAA,OAAO,EAA8C,QAAQ,EAAE,MAAM,YAAY,CAAC;AAClF,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC;;;;;;;;;;GAUG;AACH,qBAAa,SAAU,SAAQ,QAAQ;aAiBP,KAAK,EAAE,IAAI;IAhBvC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS;IAIrC,MAAM,CAAC,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS;IAIvD,MAAM,CAAC,2BAA2B,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS;IAI5D,MAAM,CAAC,GAAG,IAAI,SAAS;gBAIK,KAAK,GAAE,IAAiB;IAKpD,IAAI,CAAC,OAAO,EAAE,SAAS,GAAG,QAAQ;IAKlC,IAAI,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS;IAKnC,IAAI,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS;IAKnC,QAAQ,CAAC,OAAO,EAAE,SAAS,GAAG,OAAO;IAKrC,eAAe,CAAC,OAAO,EAAE,SAAS,GAAG,OAAO;IAK5C,OAAO,CAAC,OAAO,EAAE,SAAS,GAAG,OAAO;IAKpC,cAAc,CAAC,OAAO,EAAE,SAAS,GAAG,OAAO;IAK3C,cAAc,IAAI,MAAM;IAIxB,SAAS,IAAI,MAAM;IAInB,MAAM,IAAI,MAAM;IAIhB,WAAW,IAAI,MAAM;IAIrB,QAAQ,IAAI,MAAM;IAIlB,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM;CAG7B"}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.Timestamp = void 0;
|
|
7
|
-
const moment_1 = __importDefault(require("moment"));
|
|
8
4
|
const tiny_types_1 = require("tiny-types");
|
|
9
5
|
const util_1 = require("util");
|
|
10
6
|
const Duration_1 = require("./Duration");
|
|
@@ -24,11 +20,11 @@ class Timestamp extends tiny_types_1.TinyType {
|
|
|
24
20
|
static fromJSON(v) {
|
|
25
21
|
return new Timestamp(new Date((0, tiny_types_1.ensure)(Timestamp.name, v, isSerialisedISO8601Date())));
|
|
26
22
|
}
|
|
27
|
-
static fromTimestampInSeconds(
|
|
28
|
-
return Timestamp.fromTimestampInMilliseconds(
|
|
23
|
+
static fromTimestampInSeconds(value) {
|
|
24
|
+
return Timestamp.fromTimestampInMilliseconds(value * 1000);
|
|
29
25
|
}
|
|
30
|
-
static fromTimestampInMilliseconds(
|
|
31
|
-
return new Timestamp(
|
|
26
|
+
static fromTimestampInMilliseconds(value) {
|
|
27
|
+
return new Timestamp(new Date(value));
|
|
32
28
|
}
|
|
33
29
|
static now() {
|
|
34
30
|
return new Timestamp();
|
|
@@ -40,15 +36,15 @@ class Timestamp extends tiny_types_1.TinyType {
|
|
|
40
36
|
}
|
|
41
37
|
diff(another) {
|
|
42
38
|
(0, tiny_types_1.ensure)('timestamp', another, (0, tiny_types_1.isDefined)());
|
|
43
|
-
return new Duration_1.Duration(Math.abs(
|
|
39
|
+
return new Duration_1.Duration(Math.abs(this.toMilliseconds() - another.toMilliseconds()));
|
|
44
40
|
}
|
|
45
41
|
plus(duration) {
|
|
46
42
|
(0, tiny_types_1.ensure)('duration', duration, (0, tiny_types_1.isDefined)());
|
|
47
|
-
return new Timestamp(
|
|
43
|
+
return new Timestamp(new Date(this.toMilliseconds() + duration.inMilliseconds()));
|
|
48
44
|
}
|
|
49
45
|
less(duration) {
|
|
50
46
|
(0, tiny_types_1.ensure)('duration', duration, (0, tiny_types_1.isDefined)());
|
|
51
|
-
return new Timestamp(
|
|
47
|
+
return new Timestamp(new Date(this.toMilliseconds() - duration.inMilliseconds()));
|
|
52
48
|
}
|
|
53
49
|
isBefore(another) {
|
|
54
50
|
(0, tiny_types_1.ensure)('timestamp', another, (0, tiny_types_1.isDefined)());
|
|
@@ -67,10 +63,10 @@ class Timestamp extends tiny_types_1.TinyType {
|
|
|
67
63
|
return this.value.getTime() >= another.value.getTime();
|
|
68
64
|
}
|
|
69
65
|
toMilliseconds() {
|
|
70
|
-
return
|
|
66
|
+
return this.value.getTime();
|
|
71
67
|
}
|
|
72
68
|
toSeconds() {
|
|
73
|
-
return
|
|
69
|
+
return Math.floor(this.toMilliseconds() / 1000);
|
|
74
70
|
}
|
|
75
71
|
toJSON() {
|
|
76
72
|
return this.value.toJSON();
|
|
@@ -86,7 +82,36 @@ class Timestamp extends tiny_types_1.TinyType {
|
|
|
86
82
|
}
|
|
87
83
|
}
|
|
88
84
|
exports.Timestamp = Timestamp;
|
|
85
|
+
/**
|
|
86
|
+
* Based on the implementation by Brock Adams:
|
|
87
|
+
* - https://stackoverflow.com/a/3143231/264502 by Brock Adams
|
|
88
|
+
* - https://www.w3.org/TR/NOTE-datetime
|
|
89
|
+
*/
|
|
89
90
|
function isSerialisedISO8601Date() {
|
|
90
|
-
|
|
91
|
+
const yyyyMMdd = `\\d{4}-[01]\\d-[0-3]\\d`;
|
|
92
|
+
const hh = `[0-2]\\d`;
|
|
93
|
+
const mm = `[0-5]\\d`;
|
|
94
|
+
const ss = `[0-5]\\d`;
|
|
95
|
+
const ms = `\\d+`;
|
|
96
|
+
const T = `[Tt\\s]`;
|
|
97
|
+
const offset = `[+-]${hh}:${mm}|Z`;
|
|
98
|
+
const pattern = new RegExp('^' + [
|
|
99
|
+
// Full precision - YYYY-MM-DDThh:mm:ss.sss
|
|
100
|
+
`(${yyyyMMdd}${T}${hh}:${mm}:${ss}\\.${ms}(${offset})?)`,
|
|
101
|
+
// No milliseconds - YYYY-MM-DDThh:mm:ss
|
|
102
|
+
`(${yyyyMMdd}${T}${hh}:${mm}:${ss}(${offset})?)`,
|
|
103
|
+
// No seconds - YYYY-MM-DDThh:mm
|
|
104
|
+
`(${yyyyMMdd}${T}${hh}:${mm}(${offset})?)`,
|
|
105
|
+
// Just the date - YYYY-MM-DD
|
|
106
|
+
`(${yyyyMMdd})`,
|
|
107
|
+
].join('|') + '$');
|
|
108
|
+
return tiny_types_1.Predicate.to(`follow the ISO8601 format: YYYY-MM-DD[Thh:mm[:ss[.sss]]]`, (value) => {
|
|
109
|
+
if (!pattern.test(value)) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
const date = new Date(value);
|
|
113
|
+
return date instanceof Date
|
|
114
|
+
&& !Number.isNaN(date.getTime());
|
|
115
|
+
});
|
|
91
116
|
}
|
|
92
117
|
//# sourceMappingURL=Timestamp.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Timestamp.js","sourceRoot":"","sources":["../../../../src/screenplay/time/models/Timestamp.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Timestamp.js","sourceRoot":"","sources":["../../../../src/screenplay/time/models/Timestamp.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@serenity-js/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.16.0",
|
|
4
4
|
"description": "Serenity/JS Screenplay, reporting engine and core interfaces.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Jan Molak",
|
|
@@ -40,7 +40,6 @@
|
|
|
40
40
|
"fast-glob": "3.3.2",
|
|
41
41
|
"filenamify": "4.3.0",
|
|
42
42
|
"graceful-fs": "4.2.11",
|
|
43
|
-
"moment": "2.30.1",
|
|
44
43
|
"semver": "7.5.4",
|
|
45
44
|
"tiny-types": "1.21.0",
|
|
46
45
|
"upath": "2.0.1",
|
|
@@ -72,5 +71,5 @@
|
|
|
72
71
|
"engines": {
|
|
73
72
|
"node": "^16.13 || ^18.12 || ^20"
|
|
74
73
|
},
|
|
75
|
-
"gitHead": "
|
|
74
|
+
"gitHead": "242771e55bd6becc5baeaac03edf945e4cdaf7a4"
|
|
76
75
|
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { ConfigurationError } from '../errors';
|
|
2
|
+
import { CapabilityTag, FeatureTag, Tag, ThemeTag } from '../model';
|
|
3
|
+
import type { FileSystem } from './FileSystem';
|
|
4
|
+
import { Path } from './Path';
|
|
5
|
+
|
|
6
|
+
export class RequirementsHierarchy {
|
|
7
|
+
|
|
8
|
+
private root: Path;
|
|
9
|
+
|
|
10
|
+
private static readonly specDirectoryCandidates = [
|
|
11
|
+
`features`,
|
|
12
|
+
`specs`,
|
|
13
|
+
`spec`,
|
|
14
|
+
`tests`,
|
|
15
|
+
`test`,
|
|
16
|
+
`src`,
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
constructor(
|
|
20
|
+
private readonly fileSystem: FileSystem,
|
|
21
|
+
private readonly userDefinedSpecDirectory?: Path,
|
|
22
|
+
) {
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
requirementTagsFor(pathToSpec: Path, featureName?: string): Tag[] {
|
|
26
|
+
const [ fileBasedFeatureName, capabilityName, ...themeNames ] = this.hierarchyFor(pathToSpec).reverse().filter(segment => !['.', '..'].includes(segment));
|
|
27
|
+
|
|
28
|
+
const themeTags = themeNames.reverse().map(themeName => Tag.humanReadable(ThemeTag, themeName));
|
|
29
|
+
const capabilityTag = capabilityName && Tag.humanReadable(CapabilityTag, capabilityName);
|
|
30
|
+
const featureTag = featureName
|
|
31
|
+
? new FeatureTag(featureName)
|
|
32
|
+
: Tag.humanReadable(FeatureTag, fileBasedFeatureName)
|
|
33
|
+
|
|
34
|
+
return [
|
|
35
|
+
...themeTags,
|
|
36
|
+
capabilityTag,
|
|
37
|
+
featureTag
|
|
38
|
+
].filter(Boolean);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
hierarchyFor(pathToSpec: Path): string[] {
|
|
42
|
+
const relative = this.rootDirectory().relative(pathToSpec);
|
|
43
|
+
|
|
44
|
+
return relative.split().map((segment, i, segments) => {
|
|
45
|
+
// return all the segments as-is, except for the last one
|
|
46
|
+
if (i < segments.length - 1) {
|
|
47
|
+
return segment;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Strip the extension, like `.feature` or `.spec.ts`
|
|
51
|
+
const firstDotIndex = segment.indexOf('.');
|
|
52
|
+
return firstDotIndex === -1
|
|
53
|
+
? segment
|
|
54
|
+
: segment.slice(0, firstDotIndex);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
rootDirectory(): Path {
|
|
59
|
+
if (!this.root) {
|
|
60
|
+
this.root = this.userDefinedSpecDirectory
|
|
61
|
+
? this.resolve(this.userDefinedSpecDirectory)
|
|
62
|
+
: this.guessRootDirectory();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return this.root;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private guessRootDirectory(): Path {
|
|
69
|
+
for (const candidate of RequirementsHierarchy.specDirectoryCandidates) {
|
|
70
|
+
const candidateSpecDirectory = Path.from(candidate);
|
|
71
|
+
if (this.fileSystem.exists(Path.from(candidate))) {
|
|
72
|
+
return this.fileSystem.resolve(candidateSpecDirectory);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// default to current working directory
|
|
77
|
+
return this.fileSystem.resolve(Path.from('.'));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private resolve(userDefinedRootDirectory: Path): Path {
|
|
81
|
+
if (!this.fileSystem.exists(userDefinedRootDirectory)) {
|
|
82
|
+
throw new ConfigurationError(`Configured specDirectory \`${ userDefinedRootDirectory }\` does not exist`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return this.fileSystem.resolve(userDefinedRootDirectory);
|
|
86
|
+
}
|
|
87
|
+
}
|
package/src/io/index.ts
CHANGED
package/src/model/tags/Tag.ts
CHANGED
|
@@ -11,7 +11,7 @@ export abstract class Tag extends TinyType {
|
|
|
11
11
|
// based on https://github.com/serenity-bdd/serenity-core/blob/8f7d14c6dad47bb58a1585fef5f9d9a44bb963fd/serenity-model/src/main/java/net/thucydides/core/requirements/AbstractRequirementsTagProvider.java#L36
|
|
12
12
|
const name = String(tagName)
|
|
13
13
|
.trim()
|
|
14
|
-
.match(/[\dA-Z]{2,}(?=[A-Z][a-z]+\d*|\b)|[A-Z]?[a-z]+\d*|[A-Z]|\d+/g)
|
|
14
|
+
.match(/[\dA-Z]{2,}(?=[A-Z][a-z]+\d*|\b)|[A-Z]?[a-z-]+\d*|[A-Z]|\d+/g)
|
|
15
15
|
.map(chunk => /^[A-Z]+$/.test(chunk) ? chunk : chunk.toLowerCase())
|
|
16
16
|
.join('_')
|
|
17
17
|
.replaceAll(/[\s_]+/g, ' ')
|
package/src/screenplay/Actor.ts
CHANGED
|
@@ -174,10 +174,7 @@ export class Actor implements PerformsActivities,
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
/**
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
* @param artifact
|
|
180
|
-
* @param name
|
|
177
|
+
* @inheritDoc
|
|
181
178
|
*/
|
|
182
179
|
collect(artifact: Artifact, name?: string | Name): void {
|
|
183
180
|
this.stage.announce(new ActivityRelatedArtifactGenerated(
|
|
@@ -15,6 +15,60 @@ export interface CollectsArtifacts {
|
|
|
15
15
|
/**
|
|
16
16
|
* Makes the {@apilink Actor} collect an {@apilink Artifact} so that it can be included in the test report.
|
|
17
17
|
*
|
|
18
|
+
* #### Implementing a custom interaction to attach artifacts
|
|
19
|
+
*
|
|
20
|
+
* ```ts
|
|
21
|
+
* import * as fs from 'node:fs'
|
|
22
|
+
* import { Answerable, Interaction } from '@serenity-js/core'
|
|
23
|
+
* import { Path } from '@serenity-js/core/lib/io'
|
|
24
|
+
* import { Name, TextData } from '@serenity-js/core/lib/model'
|
|
25
|
+
*
|
|
26
|
+
* export class Attach {
|
|
27
|
+
*
|
|
28
|
+
* static contentsOf = (pathToFile: Path): Interaction =>
|
|
29
|
+
* Interaction.where(`#actor attaches contents of ${ pathToFile.basename() }`, async actor => {
|
|
30
|
+
* const data = fs.readFileSync(pathToFile.value).toString('utf-8');
|
|
31
|
+
*
|
|
32
|
+
* actor.collect(
|
|
33
|
+
* TextData.fromJSON({ contentType: 'text/plain', data }),
|
|
34
|
+
* new Name(pathToFile.basename()),
|
|
35
|
+
* )
|
|
36
|
+
* })
|
|
37
|
+
*
|
|
38
|
+
* static textData = (contents: Answerable<string>, name?: string): Interaction =>
|
|
39
|
+
* Interaction.where(`#actor attaches text data`, async actor => {
|
|
40
|
+
* const data = await actor.answer(contents);
|
|
41
|
+
*
|
|
42
|
+
* actor.collect(
|
|
43
|
+
* TextData.fromJSON({ contentType: 'text/plain', data }),
|
|
44
|
+
* name && new Name(name),
|
|
45
|
+
* )
|
|
46
|
+
* })
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* #### Attaching plain text
|
|
51
|
+
*
|
|
52
|
+
* ```ts
|
|
53
|
+
* import { actorCalled } from '@serenity-js/core'
|
|
54
|
+
* import { Path } from '@serenity-js/core/lib/io'
|
|
55
|
+
*
|
|
56
|
+
* actorCalled('Alice').attemptsTo(
|
|
57
|
+
* Attach.textData('some text', 'some name'),
|
|
58
|
+
* )
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* #### Attaching contents of a text file
|
|
62
|
+
*
|
|
63
|
+
* ```ts
|
|
64
|
+
* import { actorCalled } from '@serenity-js/core'
|
|
65
|
+
* import { Log } from '@serenity-js/core'
|
|
66
|
+
*
|
|
67
|
+
* actorCalled('Alice').attemptsTo(
|
|
68
|
+
* Attach.contentsOf(Path.from(__dirname, 'output/server.log')),
|
|
69
|
+
* )
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
18
72
|
* @param artifact
|
|
19
73
|
* The artifact to be collected, such as {@apilink JSONData}
|
|
20
74
|
*
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { QuestionAdapter } from '..';
|
|
2
|
+
import { type Answerable,Question } from '..';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* This question masks sensitive data handled by the actors and prevents
|
|
6
|
+
* it from being shown in Serenity/JS reports and console logs.
|
|
7
|
+
* You should use it to wrap passwords, secret tokens, phone numbers,
|
|
8
|
+
* credit card numbers, or any other personally identifiable information (PII).
|
|
9
|
+
* However, even though the wrapped value is masked in the output,
|
|
10
|
+
* you can still retrieve the unmasked value by making the actor answer
|
|
11
|
+
* the question in your custom interactions.
|
|
12
|
+
*
|
|
13
|
+
* @group Questions
|
|
14
|
+
*/
|
|
15
|
+
export class Masked {
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Retrieves the value of a sensitive parameter and mask it in any report.
|
|
19
|
+
*
|
|
20
|
+
* #### Example
|
|
21
|
+
*
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { actorCalled, Masked } from '@serenity-js/core';
|
|
24
|
+
* import { Ensure, equals } from '@serenity-js/assertions';
|
|
25
|
+
*
|
|
26
|
+
* await actorCalled('John')
|
|
27
|
+
* .attemptsTo(
|
|
28
|
+
* Enter.theValue(Masked.valueOf('your little secret').into(Form.exampleInput())
|
|
29
|
+
* );
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @param parameter - An {@link Answerable} representing the masked value.
|
|
33
|
+
* @returns A {@link QuestionAdapter} representing the masked value.
|
|
34
|
+
*/
|
|
35
|
+
static valueOf(parameter: Answerable<string>) : QuestionAdapter<string> {
|
|
36
|
+
return Question.about('[a masked value]', async actor => actor.answer(parameter))
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import moment from 'moment';
|
|
2
1
|
import { ensure, isDefined, isInstanceOf, Predicate, TinyType } from 'tiny-types';
|
|
3
2
|
import { inspect } from 'util';
|
|
4
3
|
|
|
@@ -20,12 +19,12 @@ export class Timestamp extends TinyType {
|
|
|
20
19
|
return new Timestamp(new Date(ensure(Timestamp.name, v, isSerialisedISO8601Date())));
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
static fromTimestampInSeconds(
|
|
24
|
-
return Timestamp.fromTimestampInMilliseconds(
|
|
22
|
+
static fromTimestampInSeconds(value: number): Timestamp {
|
|
23
|
+
return Timestamp.fromTimestampInMilliseconds(value * 1000);
|
|
25
24
|
}
|
|
26
25
|
|
|
27
|
-
static fromTimestampInMilliseconds(
|
|
28
|
-
return new Timestamp(
|
|
26
|
+
static fromTimestampInMilliseconds(value: number): Timestamp {
|
|
27
|
+
return new Timestamp(new Date(value));
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
static now(): Timestamp {
|
|
@@ -39,17 +38,17 @@ export class Timestamp extends TinyType {
|
|
|
39
38
|
|
|
40
39
|
diff(another: Timestamp): Duration {
|
|
41
40
|
ensure('timestamp', another, isDefined());
|
|
42
|
-
return new Duration(Math.abs(
|
|
41
|
+
return new Duration(Math.abs(this.toMilliseconds() - another.toMilliseconds()));
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
plus(duration: Duration): Timestamp {
|
|
46
45
|
ensure('duration', duration, isDefined());
|
|
47
|
-
return new Timestamp(
|
|
46
|
+
return new Timestamp(new Date(this.toMilliseconds() + duration.inMilliseconds()));
|
|
48
47
|
}
|
|
49
48
|
|
|
50
49
|
less(duration: Duration): Timestamp {
|
|
51
50
|
ensure('duration', duration, isDefined());
|
|
52
|
-
return new Timestamp(
|
|
51
|
+
return new Timestamp(new Date(this.toMilliseconds() - duration.inMilliseconds()));
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
isBefore(another: Timestamp): boolean {
|
|
@@ -73,11 +72,11 @@ export class Timestamp extends TinyType {
|
|
|
73
72
|
}
|
|
74
73
|
|
|
75
74
|
toMilliseconds(): number {
|
|
76
|
-
return
|
|
75
|
+
return this.value.getTime();
|
|
77
76
|
}
|
|
78
77
|
|
|
79
78
|
toSeconds(): number {
|
|
80
|
-
return
|
|
79
|
+
return Math.floor(this.toMilliseconds() / 1_000);
|
|
81
80
|
}
|
|
82
81
|
|
|
83
82
|
toJSON(): string {
|
|
@@ -97,7 +96,41 @@ export class Timestamp extends TinyType {
|
|
|
97
96
|
}
|
|
98
97
|
}
|
|
99
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Based on the implementation by Brock Adams:
|
|
101
|
+
* - https://stackoverflow.com/a/3143231/264502 by Brock Adams
|
|
102
|
+
* - https://www.w3.org/TR/NOTE-datetime
|
|
103
|
+
*/
|
|
100
104
|
function isSerialisedISO8601Date(): Predicate<string> {
|
|
101
|
-
|
|
102
|
-
|
|
105
|
+
|
|
106
|
+
const yyyyMMdd = `\\d{4}-[01]\\d-[0-3]\\d`;
|
|
107
|
+
const hh = `[0-2]\\d`;
|
|
108
|
+
const mm = `[0-5]\\d`;
|
|
109
|
+
const ss = `[0-5]\\d`;
|
|
110
|
+
const ms = `\\d+`;
|
|
111
|
+
const T = `[Tt\\s]`;
|
|
112
|
+
const offset = `[+-]${hh}:${mm}|Z`;
|
|
113
|
+
|
|
114
|
+
const pattern = new RegExp('^' + [
|
|
115
|
+
// Full precision - YYYY-MM-DDThh:mm:ss.sss
|
|
116
|
+
`(${yyyyMMdd}${T}${hh}:${mm}:${ss}\\.${ms}(${offset})?)`,
|
|
117
|
+
// No milliseconds - YYYY-MM-DDThh:mm:ss
|
|
118
|
+
`(${yyyyMMdd}${T}${hh}:${mm}:${ss}(${offset})?)`,
|
|
119
|
+
// No seconds - YYYY-MM-DDThh:mm
|
|
120
|
+
`(${yyyyMMdd}${T}${hh}:${mm}(${offset})?)`,
|
|
121
|
+
// Just the date - YYYY-MM-DD
|
|
122
|
+
`(${yyyyMMdd})`,
|
|
123
|
+
].join('|') + '$');
|
|
124
|
+
|
|
125
|
+
return Predicate.to(`follow the ISO8601 format: YYYY-MM-DD[Thh:mm[:ss[.sss]]]`, (value: string) => {
|
|
126
|
+
|
|
127
|
+
if (! pattern.test(value)) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const date = new Date(value);
|
|
132
|
+
|
|
133
|
+
return date instanceof Date
|
|
134
|
+
&& ! Number.isNaN(date.getTime());
|
|
135
|
+
});
|
|
103
136
|
}
|