Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
b01d0a3
test(empower-core): more tests on defaultOptions
twada Jul 26, 2018
3d4a9d0
chore: run tests on Babel7
twada Jul 22, 2018
b746665
chore: use Babel7 stable
twada Nov 21, 2018
a04d9e3
chore: remove stage preset from deprecated under Babel7
twada Nov 21, 2018
5d502dd
feat(empower-core): support assertions returing Promises (e.g. assert…
twada Jul 26, 2018
57022b3
feat(empower-core): surround with try-catch to make onError and onRej…
twada Jul 26, 2018
3b25f88
feat(empower-core): default implementations of `onFulfilled` and `onR…
twada Jul 26, 2018
d1d599d
docs(empower-core): add documentation of `onFulfilled` and `onRejected`
twada Jul 26, 2018
de6daf9
chore(empower-core): PoC implementation of power-assert-2 runtime side
twada Aug 2, 2018
4d33d1c
chore(empower-core): define hidden flag to callee to enable runtime f…
twada Aug 6, 2018
06a1e68
feat: put AssertionRecorder in place of assertion message argument
twada Aug 7, 2018
75ef8d5
refactor: now ArgumentRecorder knows AssertionMetadata
twada Aug 8, 2018
93a12d4
refactor: stop handling message argument since all arguments are reco…
twada Aug 9, 2018
c3ed497
feat: support `assert.throws`, `assert.doesNotThrow`
twada Aug 23, 2018
67341a7
test: support `assert.throws`, `assert.doesNotThrow`
twada Nov 21, 2018
6725cc3
feat: update argument itself to make side-effect visible from caller
twada Nov 21, 2018
87516f2
feat(power-assert-context-reducer-comparison): add `expected`, `actua…
twada Nov 22, 2018
2894430
feat: merge reducers into renderers and name it `pipeline`
twada Nov 22, 2018
ca5a668
feat(power-assert-context-formatter): drop support of legacy style cu…
twada Nov 22, 2018
ae49dd9
docs(power-assert-context-formatter): refer to pipeline
twada Nov 22, 2018
9b7f298
feat: modernize codebase stop using ponyfills and core-js
twada Nov 22, 2018
ab5c580
style: format with semistandard
twada Nov 22, 2018
2a0d644
style: format with semistandard
twada Nov 22, 2018
94f55a5
chore(power-assert-context-reducer-ast): update espurify
twada Nov 23, 2018
e0d794d
chore: update stringifier
twada Nov 23, 2018
3309557
test: acceptance tests
twada Nov 22, 2018
37e7878
test: modernize new implementation
twada Nov 22, 2018
4908a60
style: format with semistandard
twada Nov 22, 2018
5a6dbae
chore: use public branch
twada Nov 23, 2018
eaeed24
Merge branch 'acceptance-tests' into modernize
twada Nov 23, 2018
d59cedd
Merge branch 'modernize' into power-assert-2
twada Nov 23, 2018
f3ea85d
chore: arrow functions
twada Jan 16, 2019
8c2ed28
feat: add matchIndex to powerAssertContext.args
twada Jan 23, 2019
60dee83
test: more examples
twada Jan 23, 2019
42f3825
chore: prefer mutable style since context object is shared across ren…
twada May 11, 2019
ddc1f50
chore: ignore .idea
twada Jun 11, 2019
e35d01b
chore(empower-core): make call-signature optimistic ranged
twada Jun 11, 2019
10a30e9
chore(sandbox): testing with babel-plugin-espower defaults
twada Jun 11, 2019
2b27a16
chore(sandbox): ignore generated files
twada Jun 11, 2019
1e60090
docs: mark properties used by AVA as API
twada Jun 12, 2019
859a5f8
test(power-assert-2): testing deepStrictEqual stringify depth configu…
twada Jun 12, 2019
08b6718
feat(power-assert-2): working with power-assert-v2 tranpiler interop
twada Jun 12, 2019
9c271c3
test(empower-core): assert.rejects on Node8 only accepts functions
twada Jun 12, 2019
7eb7d1b
feat(power-assert-2): override assert.rejects/doesNotReject on Node8
twada Jul 10, 2019
b8bb9fa
refactor(power-assert-2): remove dirty hack fixing unchanged error me…
twada Jul 10, 2019
b9ab54b
chore: report test results in dots
twada Jul 10, 2019
f5898dd
test(power-assert-context-traversal): now transpiler-side embeds its …
twada Jul 10, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
node_modules
.DS_Store
*.log
.idea
sandbox/power-assert-2/generated/
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[![power-assert][power-assert-banner]][power-assert-url]

[![Build Status][travis-image]][travis-url]
[![Code Style][style-image]][style-url]
[![License][license-image]][license-url]

Reorganize [empower](https://github.com/power-assert-js/empower), [power-assert-formatter](https://github.com/power-assert-js/power-assert-formatter) and [power-assert-renderers](https://github.com/twada/power-assert-renderers) into [monorepo](https://github.com/babel/babel/blob/master/doc/design/monorepo.md) structure.
Expand Down Expand Up @@ -57,5 +58,8 @@ Licensed under the [MIT](https://github.com/twada/power-assert-runtime/blob/mast
[travis-url]: https://travis-ci.org/twada/power-assert-runtime
[travis-image]: https://secure.travis-ci.org/twada/power-assert-runtime.svg?branch=master

[style-url]: https://github.com/Flet/semistandard
[style-image]: https://img.shields.io/badge/code%20style-semistandard-brightgreen.svg

[license-url]: https://github.com/twada/power-assert-runtime/blob/master/LICENSE
[license-image]: https://img.shields.io/badge/license-MIT-brightgreen.svg
20 changes: 11 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@
"url": "https://github.com/twada/power-assert-runtime/issues"
},
"devDependencies": {
"babel-core": "^6.1.0",
"babel-plugin-espower": "^2.3.1",
"babel-plugin-transform-function-bind": "^6.1.0",
"babel-preset-es2015": "^6.1.0",
"babel-preset-react": "^6.1.0",
"babel-preset-stage-2": "^6.1.0",
"core-js": "^2.0.0",
"@babel/core": "^7.0.0",
"@babel/plugin-proposal-function-bind": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"@babel/preset-react": "^7.0.0",
"babel-plugin-espower": "power-assert-js/babel-plugin-espower#power-assert-2",
"lerna": "^2.11.0",
"mocha": "^5.0.0"
"mocha": "^5.0.0",
"semistandard": "^13.0.1",
"snazzy": "^8.0.0"
},
"homepage": "https://github.com/twada/power-assert-runtime",
"keywords": [
Expand All @@ -33,6 +33,8 @@
"scripts": {
"bootstrap": "lerna bootstrap",
"lerna": "lerna",
"test": "mocha --timeout 0 packages/*/test/*.js"
"fmt": "semistandard --fix packages/*/index.js packages/*/lib/*.js",
"lint": "semistandard --verbose packages/*/index.js packages/*/lib/*.js | snazzy",
"test": "mocha --timeout 0 --reporter dot packages/*/test/*test.js"
}
}
35 changes: 29 additions & 6 deletions packages/empower-core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ See [CHANGELOG](https://github.com/twada/power-assert-runtime/packages/empower-c
API
---------------------------------------

### var enhancedAssert = empowerCore(originalAssert, [options])
### const enhancedAssert = empowerCore(originalAssert, [options])

| return type |
|:-----------------------|
Expand Down Expand Up @@ -78,8 +78,8 @@ If `false`, empower-core mimics originalAssert as new object/function, so `origi
`bindReceiver` defaults to `true`, meaning assertion methods have their `this` value bound to the original assertion. Setting `bindReceiver` to false causes the `this` reference to be passed through from the actual invocation.


#### options.onError
#### options.onSuccess
#### options.onError(errorEvent)
#### options.onSuccess(successEvent)

| type | default value |
|:-----------|:--------------|
Expand All @@ -89,6 +89,8 @@ Both methods are called with a single `event` argument, it will have the followi

- `event.enhanced` - `true` for methods matching `patterns`. `false` for methods matching `wrapOnlyPatterns`.

- `event.config` - actual configuration object that is `Object.assign`ed with `defaultOptions()` and `options`.

- `event.originalMessage` - The actual value the user provided for optional `message` parameter. This will be `undefined` if the user did not provide a value, even if the underlying assertion provides a default message.

- `event.defaultMessage` - If you use objects instead of strings to specify patterns (see below), the `defaultMessage` metadata will be copied directly on the event object.
Expand All @@ -107,14 +109,35 @@ Both methods are called with a single `event` argument, it will have the followi

```js
function onError (errorEvent) {
var e = errorEvent.error;
const e = errorEvent.error;
if (errorEvent.powerAssertContext && /^AssertionError/.test(e.name)) {
e.powerAssertContext = errorEvent.powerAssertContext;
}
throw e;
}
```

#### options.onFulfilled(errorEvent, resolve, reject)
#### options.onRejected(successEvent, resolve, reject)

| type | default value |
|:-----------|:--------------|
| `function` | (function defined in `empowerCore.defaultOptions()`) |

Handler functions to deal with Promises returned from target assertions. `onFulfilled` is called when assertion is resolved. `onRejected` is called when assertion is rejected.

Both methods are called with three arguments, `event`, `resolve` and `reject`.

| arg | type | description |
|:-----------|:--------------|:--------------|
| `event` | `object` | same as `event` argument of `onError` or `onSuccess` |
| `resolve` | `function` | same as `resolve` callback for Promise |
| `reject` | `function` | same as `reject` callback for Promise |


Default implementations of `onFulfilled` and `onRejected` simply delegate to `onSuccess` and `onError` so you don't need to override `onFulfilled` and `onRejected` in most cases.


#### options.modifyMessageBeforeAssert

| type | default value |
Expand Down Expand Up @@ -171,7 +194,7 @@ Methods matching these patterns will not be instrumented by the code transform,

Similar to the `options.patterns`, you may supply objects with a `pattern` member, and the additional metadata will be passed to the assertion listeners.

### var options = empowerCore.defaultOptions();
### const options = empowerCore.defaultOptions();

Returns default options object for `empowerCore` function. In other words, returns

Expand Down Expand Up @@ -199,7 +222,7 @@ with sensible default for `onError` and `onSuccess`

```js
function onError (errorEvent) {
var e = errorEvent.error;
const e = errorEvent.error;
if (errorEvent.powerAssertContext && e.name === 'AssertionError') {
e.powerAssertContext = errorEvent.powerAssertContext;
}
Expand Down
93 changes: 44 additions & 49 deletions packages/empower-core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@
* Licensed under the MIT license.
* https://github.com/twada/power-assert-runtime/blob/master/LICENSE
*/
var create = require('core-js/library/fn/object/create');
var assign = require('core-js/library/fn/object/assign');
var defaultOptions = require('./lib/default-options');
var Decorator = require('./lib/decorator');
var define = require('./lib/define-properties');
var slice = Array.prototype.slice;
const defaultOptions = require('./lib/default-options');
const Decorator = require('./lib/decorator');
const define = require('./lib/define-properties');
const slice = Array.prototype.slice;
const isEmpowered = (assertObjectOrFunction) => assertObjectOrFunction._empowered;

/**
* Enhance Power Assert feature to assert function/object.
Expand All @@ -21,58 +20,54 @@ var slice = Array.prototype.slice;
* @return enhanced assert function/object
*/
function empowerCore (assert, options) {
var typeOfAssert = (typeof assert);
var enhancedAssert;
if ((typeOfAssert !== 'object' && typeOfAssert !== 'function') || assert === null) {
throw new TypeError('empower-core argument should be a function or object.');
}
if (isEmpowered(assert)) {
return assert;
}
switch (typeOfAssert) {
const typeOfAssert = (typeof assert);
if ((typeOfAssert !== 'object' && typeOfAssert !== 'function') || assert === null) {
throw new TypeError('empower-core argument should be a function or object.');
}
if (isEmpowered(assert)) {
return assert;
}
let enhancedAssert;
switch (typeOfAssert) {
case 'function':
enhancedAssert = empowerAssertFunction(assert, options);
break;
enhancedAssert = empowerAssertFunction(assert, options);
break;
case 'object':
enhancedAssert = empowerAssertObject(assert, options);
break;
enhancedAssert = empowerAssertObject(assert, options);
break;
default:
throw new Error('Cannot be here');
}
define(enhancedAssert, { _empowered: true });
return enhancedAssert;
throw new Error('Cannot be here');
}
define(enhancedAssert, { _empowered: true });
return enhancedAssert;
}

function empowerAssertObject (assertObject, options) {
var config = assign(defaultOptions(), options);
var target = config.destructive ? assertObject : create(assertObject);
var decorator = new Decorator(target, config);
return assign(target, decorator.enhancement());
const config = Object.assign(defaultOptions(), options);
const target = config.destructive ? assertObject : Object.create(assertObject);
const decorator = new Decorator(target, config);
return Object.assign(target, decorator.enhancement());
}

function empowerAssertFunction (assertFunction, options) {
var config = assign(defaultOptions(), options);
if (config.destructive) {
throw new Error('cannot use destructive:true to function.');
}
var decorator = new Decorator(assertFunction, config);
var enhancement = decorator.enhancement();
var powerAssert;
if (typeof enhancement === 'function') {
powerAssert = function powerAssert () {
return enhancement.apply(null, slice.apply(arguments));
};
} else {
powerAssert = function powerAssert () {
return assertFunction.apply(null, slice.apply(arguments));
};
}
assign(powerAssert, assertFunction);
return assign(powerAssert, enhancement);
}

function isEmpowered (assertObjectOrFunction) {
return assertObjectOrFunction._empowered;
const config = Object.assign(defaultOptions(), options);
if (config.destructive) {
throw new Error('cannot use destructive:true to function.');
}
const decorator = new Decorator(assertFunction, config);
const enhancement = decorator.enhancement();
let powerAssert;
if (typeof enhancement === 'function') {
powerAssert = function powerAssert () {
return enhancement.apply(null, slice.apply(arguments));
};
} else {
powerAssert = function powerAssert () {
return assertFunction.apply(null, slice.apply(arguments));
};
}
Object.assign(powerAssert, assertFunction);
return Object.assign(powerAssert, enhancement);
}

empowerCore.defaultOptions = defaultOptions;
Expand Down
131 changes: 74 additions & 57 deletions packages/empower-core/lib/decorate.js
Original file line number Diff line number Diff line change
@@ -1,66 +1,83 @@
'use strict';

var some = require('core-js/library/fn/array/some');
var map = require('core-js/library/fn/array/map');
const isNotCaptured = (value) => !isCaptured(value);
const isCaptured = (value) =>
(typeof value === 'object') &&
(value !== null) &&
(typeof value.powerAssertContext !== 'undefined');
// MEMO: ArgumentRecorder or AssertionMessage
const isRecorded = (value) =>
typeof value === 'object' &&
value !== null &&
typeof value.metadata === 'function' &&
typeof value.matchIndex === 'function' &&
typeof value.eject === 'function';

function decorate (callSpec, decorator) {
var numArgsToCapture = callSpec.numArgsToCapture;
module.exports = function decorate (callSpec, decorator) {
const numArgsToCapture = callSpec.numArgsToCapture;

return function decoratedAssert () {
var context, message, hasMessage = false;
return function decoratedAssert () {
const hasMessage = (numArgsToCapture === (arguments.length - 1));
let context;

// see: https://github.com/twada/empower-core/pull/8#issue-127859465
// see: https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments
var args = new Array(arguments.length);
for(var i = 0; i < args.length; ++i) {
args[i] = arguments[i];
}

if (numArgsToCapture === (args.length - 1)) {
message = args.pop();
hasMessage = true;
}

var invocation = {
thisObj: this,
values: args,
message: message,
hasMessage: hasMessage
};
// see: https://github.com/twada/empower-core/pull/8#issue-127859465
// see: https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments
const args = new Array(arguments.length);
for (let i = 0; i < args.length; ++i) {
args[i] = arguments[i];
}

if (some(args, isCaptured)) {
invocation.values = map(args.slice(0, numArgsToCapture), function (arg) {
if (isNotCaptured(arg)) {
return arg;
}
if (!context) {
context = {
source: arg.source,
args: []
};
}
context.args.push({
value: arg.powerAssertContext.value,
events: arg.powerAssertContext.events
});
return arg.powerAssertContext.value;
});
const invocation = {
thisObj: this, // be careful
values: args,
hasMessage: hasMessage
};

return decorator.concreteAssert(callSpec, invocation, context);
if (args.some(isRecorded)) {
invocation.values = args.map((arg) => {
if (!isRecorded(arg)) {
return arg;
}
if (!context) {
context = {
source: arg.metadata(), // API (used in AVA)
args: [] // API (used in AVA)
};
}
const record = arg.eject();
const matchIndex = arg.matchIndex();
if (matchIndex === -1) { // generated AssertionMessage
invocation.hasMessage = false;
} else {
return decorator.concreteAssert(callSpec, invocation);
context.args.push({
matchIndex,
value: record.value,
events: record.logs // API (used in AVA)
});
}
};
}

function isNotCaptured (value) {
return !isCaptured(value);
}

function isCaptured (value) {
return (typeof value === 'object') &&
(value !== null) &&
(typeof value.powerAssertContext !== 'undefined');
}

module.exports = decorate;
return record.value;
});
return decorator.concreteAssert(callSpec, invocation, context);
} else if (args.some(isCaptured)) {
invocation.values = args.map((arg, idx) => {
if (isNotCaptured(arg)) {
return arg;
}
if (!context) {
context = {
source: arg.source,
args: []
};
}
context.args.push({
value: arg.powerAssertContext.value,
events: arg.powerAssertContext.events
});
return arg.powerAssertContext.value;
});
return decorator.concreteAssert(callSpec, invocation, context);
} else {
return decorator.concreteAssert(callSpec, invocation);
}
};
};
Loading