-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(chai-retry-plugin): collision with chai-as-promised
plugin
#392
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,8 +4,9 @@ import { retryFunctionAndAssertions } from './helpers'; | |
import type { AssertionMethod, FunctionToRetry, AssertionStackItem, RetryOptions, PromiseLikeAssertion } from './types'; | ||
|
||
/** | ||
* Plugin that allows to re-run function passed to `expect` with new `retry` method, retrying would be performed until | ||
* the result will pass the chained assertion or timeout exceeded or retries limit reached. | ||
* Plugin that allows to re-run function passed to `expect`, in order to achieve that use new `retry` method, retrying would be performed until | ||
* the result will pass the chained assertion or timeout exceeded or retries limit reached. The assertion chain eventually returns the last | ||
* successfully asserted value. | ||
* Should be applied through `Chai.use` function, for example: | ||
* @example | ||
* ```ts | ||
|
@@ -29,67 +30,71 @@ import type { AssertionMethod, FunctionToRetry, AssertionStackItem, RetryOptions | |
* await expect(funcToRetry).retry().and.have.property('success').and.be.true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use a more realistic example: await expect(() => document.title).retry({ timeout: 10_000 }).to.equal('hello'); |
||
* ``` | ||
*/ | ||
export const chaiRetryPlugin = function (_: typeof Chai, utils: Chai.ChaiUtils) { | ||
Chai.Assertion.addMethod('retry', function (retryOptions: RetryOptions = {}): PromiseLikeAssertion { | ||
const functionToRetry: FunctionToRetry = this._obj as FunctionToRetry; | ||
const description = utils.flag(this, 'message') as string; | ||
export const chaiRetryPlugin = function (_: typeof Chai, { flag, inspect }: Chai.ChaiUtils) { | ||
Object.defineProperty(Chai.Assertion.prototype, 'retry', { | ||
value: function (retryOptions: RetryOptions = {}): PromiseLikeAssertion { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extract this to a named function instead of increasing indentation even further. |
||
const functionToRetry: FunctionToRetry = flag(this as Chai.AssertStatic, 'object') as FunctionToRetry; | ||
const description = flag(this as Chai.AssertStatic, 'message') as string; | ||
|
||
if (typeof functionToRetry !== 'function') { | ||
throw new TypeError(utils.inspect(functionToRetry) + ' is not a function.'); | ||
} | ||
if (typeof functionToRetry !== 'function') { | ||
throw new TypeError(inspect(functionToRetry) + ' is not a function.'); | ||
} | ||
|
||
const defaultRetryOptions: Required<RetryOptions> = { timeout: 5000, retries: Infinity, delay: 0 }; | ||
const options: Required<RetryOptions> = { ...defaultRetryOptions, ...retryOptions }; | ||
const defaultRetryOptions: Required<RetryOptions> = { timeout: 5000, retries: Infinity, delay: 0 }; | ||
const options: Required<RetryOptions> = { ...defaultRetryOptions, ...retryOptions }; | ||
|
||
const assertionStack: AssertionStackItem[] = []; | ||
// Fake assertion object for catching calls of chained methods | ||
const proxyTarget = new Chai.Assertion({}); | ||
const assertionStack: AssertionStackItem[] = []; | ||
// Fake assertion object for catching calls of chained methods | ||
const proxyTarget = new Chai.Assertion({}); | ||
|
||
const assertionProxy: PromiseLikeAssertion = Object.assign( | ||
new Proxy(proxyTarget, { | ||
get: function (target: Chai.Assertion, key: string, proxySelf: Chai.Assertion) { | ||
let value: Chai.Assertion | undefined; | ||
const assertionProxy: PromiseLikeAssertion = Object.assign( | ||
new Proxy(proxyTarget, { | ||
get: function (target: Chai.Assertion, key: string, proxySelf: Chai.Assertion) { | ||
let value: Chai.Assertion | undefined; | ||
|
||
try { | ||
// if `value` is a getter property that may immediately perform the assertion and throw the AssertionError | ||
value = target[key as keyof Chai.Assertion] as Chai.Assertion; | ||
} catch { | ||
// | ||
} | ||
try { | ||
// if `value` is a getter property that may immediately perform the assertion and throw the AssertionError | ||
value = target[key as keyof Chai.Assertion] as Chai.Assertion; | ||
} catch { | ||
// | ||
} | ||
|
||
if (typeof value === 'function') { | ||
return (...args: unknown[]) => { | ||
if (key === 'then') { | ||
return (value as unknown as AssertionMethod)(...args); | ||
} | ||
if (typeof value === 'function') { | ||
return (...args: unknown[]) => { | ||
if (key === 'then') { | ||
return (value as unknown as AssertionMethod)(...args); | ||
} | ||
|
||
assertionStack.push({ | ||
propertyName: key as keyof Chai.Assertion, | ||
method: value as unknown as AssertionMethod, | ||
args, | ||
}); | ||
assertionStack.push({ | ||
propertyName: key as keyof Chai.Assertion, | ||
method: value as unknown as AssertionMethod, | ||
args, | ||
}); | ||
|
||
return proxySelf; | ||
}; | ||
} else { | ||
assertionStack.push({ propertyName: key as keyof Chai.Assertion }); | ||
} | ||
return proxySelf; | ||
}; | ||
} else { | ||
assertionStack.push({ propertyName: key as keyof Chai.Assertion }); | ||
} | ||
|
||
return proxySelf; | ||
}, | ||
}), | ||
{ | ||
then: (resolve: () => void, reject: () => void) => { | ||
return retryFunctionAndAssertions({ | ||
functionToRetry, | ||
options, | ||
assertionStack, | ||
description, | ||
}).then(resolve, reject); | ||
}, | ||
} | ||
) as unknown as PromiseLikeAssertion; | ||
return proxySelf; | ||
}, | ||
}), | ||
{ | ||
then: (resolve: () => void, reject: () => void) => { | ||
return retryFunctionAndAssertions({ | ||
functionToRetry, | ||
options, | ||
assertionStack, | ||
description, | ||
}).then(resolve, reject); | ||
}, | ||
} | ||
) as unknown as PromiseLikeAssertion; | ||
|
||
return assertionProxy; | ||
return assertionProxy; | ||
}, | ||
writable: false, | ||
configurable: false, | ||
}); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,12 @@ | ||
import Chai, { expect } from 'chai'; | ||
import chaiAsPromised from 'chai-as-promised'; | ||
import { sleep } from 'promise-assist'; | ||
|
||
import { chaiRetryPlugin } from '../chai-retry-plugin/chai-retry-plugin'; | ||
|
||
Chai.use(chaiRetryPlugin); | ||
// `chai-as-promised` should be used in order to test collision between plugins | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Should be used" or "is used"? |
||
Chai.use(chaiAsPromised); | ||
|
||
describe('chai-retry-plugin', () => { | ||
it('should retry a function that eventually succeeds', async () => { | ||
|
@@ -68,7 +72,20 @@ describe('chai-retry-plugin', () => { | |
return 'Success'; | ||
}); | ||
|
||
await expect(resultFunction).to.retry({ delay: 200 }).to.equal('Success'); | ||
await expect(resultFunction).retry({ delay: 200 }).to.equal('Success'); | ||
}); | ||
|
||
it('should return value that was asserted successfully', async () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you mean by "asserted successfully"? There's no assertion here. |
||
const { resultFunction } = withCallCount((callCount: number) => { | ||
if (callCount < 3) { | ||
throw new Error('Failed'); | ||
} | ||
return 'Success'; | ||
}); | ||
|
||
const result = await expect(resultFunction).retry(); | ||
|
||
expect(result).to.equal('Success'); | ||
}); | ||
}); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand this. The words don't connect into a sentence.
Change to: