Skip to content
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

Add helpful utilities for deprecations and warnings #868

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
103 changes: 103 additions & 0 deletions addon-test-support/assertions/deprecations.js
@@ -0,0 +1,103 @@
import {
getDeprecationsDuringCallback,
getDeprecations,
} from '@ember/test-helpers';
import checkMatcher from './utils/check-matcher';

export function deprecationsInclude(expected) {
const deprecations = getDeprecations().map(
(deprecation) => deprecation.message
);

this.pushResult({
result: deprecations.indexOf(expected) > -1,
actual: deprecations,
message: `expected to find \`${expected}\` deprecation`,
});
}

export function expectDeprecations(callback, expectedDeprecations) {
const maybeThenable = getDeprecationsDuringCallback(callback);

const operation = (deprecations) => {
this.deepEqual(
deprecations.map((deprecation) => deprecation.message),
expectedDeprecations,
'Expected deprecations during test.'
);
};

if (
typeof maybeThenable === 'object' &&
maybeThenable !== null &&
typeof maybeThenable.then === 'function'
) {
return maybeThenable.then(operation);
} else {
operation(maybeThenable);
}
}

export function expectDeprecation(cb, matcher) {
const test = (deprecations, matcher) => {
const matchedDeprecations = deprecations.filter((deprecation) => {
return checkMatcher(deprecation.message, matcher);
});

this.pushResult({
result: matchedDeprecations.length !== 0,
actual: matchedDeprecations,
expected: null,
message:
'Expected deprecations during test, but no deprecations were found.',
});
};

if (typeof cb !== 'function') {
// cb is not a callback, so we assume it is the matcher
test(getDeprecations(), cb);
} else {
const maybeThenable = getDeprecationsDuringCallback(cb);
if (
maybeThenable !== null &&
typeof maybeThenable === 'object' &&
typeof maybeThenable.then === 'function'
) {
return maybeThenable.then((deprecations) => test(deprecations, matcher));
} else {
test(maybeThenable, matcher);
}
}
}

export function expectNoDeprecation(cb, matcher) {
const test = (deprecations, matcher) => {
const matchedDeprecations = deprecations.filter((deprecation) => {
return checkMatcher(deprecation.message, matcher);
});

this.pushResult({
result: matchedDeprecations.length === 0,
actual: matchedDeprecations,
expected: [],
message:
'Expected no deprecations during test, but deprecations were found.',
});
};

if (typeof cb !== 'function') {
// cb is not a callback, so we assume it is the matcher
test(getDeprecations(), cb);
} else {
const maybeThenable = getDeprecationsDuringCallback(cb);
if (
maybeThenable !== null &&
typeof maybeThenable === 'object' &&
typeof maybeThenable.then === 'function'
) {
return maybeThenable.then((deprecations) => test(deprecations, matcher));
} else {
test(maybeThenable, matcher);
}
}
}
21 changes: 21 additions & 0 deletions addon-test-support/assertions/utils/check-matcher.js
@@ -0,0 +1,21 @@
function includes(message, search) {
return message.includes
? message.includes(search)
: message.indexOf(search) !== -1;
}

// TODO: test
export default function checkMatcher(message, matcher) {
if (typeof matcher === 'string') {
return includes(message, matcher);
} else if (matcher instanceof RegExp) {
return !!message.match(matcher);
} else if (matcher) {
throw new Error(
`[ember-qunit] can only match Strings and RegExps. "${typeof matcher}" was provided.`
);
}

// No matcher always returns true. Makes the code easier elsewhere.
return true;
}
3 changes: 3 additions & 0 deletions addon-test-support/assertions/utils/to-assertion-message.js
@@ -0,0 +1,3 @@
export default function toAssertionMessage(assertion) {
return assertion.message;
}
39 changes: 39 additions & 0 deletions addon-test-support/assertions/warnings.js
@@ -0,0 +1,39 @@
import checkMatcher from './utils/check-matcher';

import { getWarnings, getWarningsDuringCallback } from '@ember/test-helpers';

export function expectNoWarning(callback) {
const warnings =
typeof callback === 'function'
? getWarningsDuringCallback(callback)
: getWarnings();

this.pushResult({
result: warnings.length === 0,
actual: warnings,
expected: [],
message: 'Expected no warnings during test, but warnings were found.',
});
}

export function expectWarning(callback, matcher) {
let warnings;
if (typeof callback === 'function') {
warnings = getWarningsDuringCallback(callback);
} else {
matcher = callback;
warnings = getWarnings();
}

const actual = warnings.filter((warning) =>
checkMatcher(warning.message, matcher)
);

const result = actual.length !== 0;
this.pushResult({
result,
actual,
expected: null,
message: 'Expected warnings during test, but no warnings were found.',
});
}
39 changes: 39 additions & 0 deletions addon-test-support/index.js
Expand Up @@ -3,6 +3,19 @@
export { default as QUnitAdapter, nonTestDoneCallback } from './adapter';
export { loadTests } from './test-loader';

export {
expectDeprecations,
deprecationsInclude,
expectDeprecation,
expectNoDeprecation,
} from './assertions/deprecations';

export {
expectWarning,
expectNoWarning,
} from './assertions/warnings';


import './qunit-configuration';

if (typeof Testem !== 'undefined') {
Expand All @@ -26,6 +39,28 @@ import { installTestNotIsolatedHook } from './test-isolation-validation';

let waitForSettled = true;

import {
expectDeprecations,
deprecationsInclude,
expectDeprecation,
expectNoDeprecation,
} from './assertions/deprecations';

import {
expectWarning,
expectNoWarning,
} from './assertions/warnings';

export function setupAsserts(assert) {
// TODO: decide which of these we should keep, which depreacte and which drop.
assert.deprecationsInclude = deprecationsInclude;
assert.deprecations = expectDeprecations;
assert.expectNoDeprecation = expectNoDeprecation;
assert.expectDeprecation = expectDeprecation; // compat
assert.expectWarning = expectWarning;
assert.expectNoWarning = expectNoWarning;
}

export function setupTest(hooks, _options) {
let options = { waitForSettled, ..._options };

Expand Down Expand Up @@ -213,5 +248,9 @@ export function start(options = {}) {
startTests();
}

if (options.setupAssertAdditions !== false) {
setupAsserts(QUnit.assert);
}

setupResetOnerror();
}
1 change: 1 addition & 0 deletions server/index.js
@@ -0,0 +1 @@
module.exports = (app) => app.get('/', (_, res) => res.redirect('/tests'));