Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 788eba34b6 | |||
| 1f31b4b0f6 | |||
| 00a8a11904 | |||
| 3899d83fb6 | |||
| 8f13684a01 | |||
| bdf63f2402 | |||
| 9c2ffae2f9 | |||
| 7b2807b321 | |||
| e930622548 | |||
| 56e2832ebe | |||
| d31d33aeb3 | |||
| e4c69e960e | |||
| a8431f33bd | |||
| 4995c967ac | |||
| 9a9d3994da | |||
| ff9feb29d3 | |||
| fee7e6e64e | |||
| 18d4d38655 | |||
| 53e9bc68d2 | |||
| 2be50e1b87 | |||
| 27a1257b6d | |||
| 75658e0566 | |||
| 85322d1877 | |||
| 6667a42301 | |||
| 020dffd504 | |||
| 4201fd848f | |||
| 9a67c4e24d |
@@ -1,5 +1,5 @@
|
|||||||
# Run tests against supported Node versions, and (except for pull requests)
|
# Run tests against supported Node versions, and (except for pull requests)
|
||||||
# against supported browsers.
|
# against supported browsers that are available on Saucelabs.
|
||||||
|
|
||||||
version: 2.1
|
version: 2.1
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ jobs:
|
|||||||
export SAUCE_TUNNEL_NAME=$CIRCLE_WORKFLOW_JOB_ID
|
export SAUCE_TUNNEL_NAME=$CIRCLE_WORKFLOW_JOB_ID
|
||||||
scripts/start-sauce-connect
|
scripts/start-sauce-connect
|
||||||
set +o errexit
|
set +o errexit
|
||||||
scripts/run-all-browsers
|
scripts/run-sauce-browsers
|
||||||
exitcode=$?
|
exitcode=$?
|
||||||
set -o errexit
|
set -o errexit
|
||||||
scripts/stop-sauce-connect
|
scripts/stop-sauce-connect
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
name: Test in latest available Safari
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * *'
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: macos-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Report Safari version
|
||||||
|
run: osascript -e 'get version of application "Safari"'
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Use Node.js 22.x
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 22.x
|
||||||
|
- run: npm install
|
||||||
|
- run: npm run build
|
||||||
|
- run: JASMINE_BROWSER=safari npm run ci
|
||||||
@@ -30,7 +30,7 @@ Microsoft Edge) as well as Node.
|
|||||||
| Environment | Supported versions |
|
| Environment | Supported versions |
|
||||||
|-------------------|----------------------------------|
|
|-------------------|----------------------------------|
|
||||||
| Node | 20, 22, 24 |
|
| Node | 20, 22, 24 |
|
||||||
| Safari | 16*, 17* |
|
| Safari | 16*, 17*, 26* |
|
||||||
| Chrome | Evergreen |
|
| Chrome | Evergreen |
|
||||||
| Firefox | Evergreen, 102*, 115*, 128*, 140 |
|
| Firefox | Evergreen, 102*, 115*, 128*, 140 |
|
||||||
| Edge | Evergreen |
|
| Edge | Evergreen |
|
||||||
|
|||||||
+12
-3
@@ -28,9 +28,18 @@ should also rev to that version.
|
|||||||
|
|
||||||
When ready to release - specs are all green and the stories are done:
|
When ready to release - specs are all green and the stories are done:
|
||||||
|
|
||||||
1. Update the release notes in `release_notes` - use the Anchorman gem to generate the markdown file and edit accordingly. Include a list of supported environments.
|
1. Update the release notes in `release_notes` - use the Anchorman gem to
|
||||||
1. Update the version in `package.json`
|
generate the Markdown file and edit accordingly. Include a list of supported
|
||||||
1. Run `npm run build`.
|
environments. Get that information from these places:
|
||||||
|
* For Node, see .circleci/config.yml or the README.
|
||||||
|
* For Firefox ESR and Safari <=17, see scripts/run-sauce-browsers or the README.
|
||||||
|
* For evergreen browsers, trigger a Circle CI run and check the
|
||||||
|
[Saucelabs dashboard](https://app.saucelabs.com/dashboard/tests?ownerId=90a771d55857492da3bd5251a2d92457&ownerType=user&ownerName=jasmine-js&start=last7days)
|
||||||
|
once it's finished.
|
||||||
|
* For Safari >17, trigger the [Safari action](https://github.com/jasmine/jasmine/actions/workflows/safari.yml)
|
||||||
|
and get the version from the output.
|
||||||
|
2. Update the version in `package.json`
|
||||||
|
3. Run `npm run build`.
|
||||||
|
|
||||||
### Commit and push core changes
|
### Commit and push core changes
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||||||
*/
|
*/
|
||||||
env.addReporter(jsApiReporter);
|
env.addReporter(jsApiReporter);
|
||||||
env.addReporter(htmlReporter);
|
env.addReporter(htmlReporter);
|
||||||
|
/**
|
||||||
|
* Configures Jasmine based on the current set of query parameters. This
|
||||||
|
* supports all parameters set by the HTML reporter as well as
|
||||||
|
* spec=partialPath, which filters out specs whose paths don't contain the
|
||||||
|
* parameter.
|
||||||
|
*/
|
||||||
env.configure(urls.configFromCurrentUrl());
|
env.configure(urls.configFromCurrentUrl());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ jasmineRequire.html = function(j$) {
|
|||||||
j$.private.SymbolsView = jasmineRequire.SymbolsView(j$);
|
j$.private.SymbolsView = jasmineRequire.SymbolsView(j$);
|
||||||
j$.private.SummaryTreeView = jasmineRequire.SummaryTreeView(j$);
|
j$.private.SummaryTreeView = jasmineRequire.SummaryTreeView(j$);
|
||||||
j$.private.FailuresView = jasmineRequire.FailuresView(j$);
|
j$.private.FailuresView = jasmineRequire.FailuresView(j$);
|
||||||
|
j$.private.PerformanceView = jasmineRequire.PerformanceView(j$);
|
||||||
|
j$.private.TabBar = jasmineRequire.TabBar(j$);
|
||||||
j$.HtmlReporter = jasmineRequire.HtmlReporter(j$);
|
j$.HtmlReporter = jasmineRequire.HtmlReporter(j$);
|
||||||
j$.HtmlReporterV2Urls = jasmineRequire.HtmlReporterV2Urls(j$);
|
j$.HtmlReporterV2Urls = jasmineRequire.HtmlReporterV2Urls(j$);
|
||||||
j$.HtmlReporterV2 = jasmineRequire.HtmlReporterV2(j$);
|
j$.HtmlReporterV2 = jasmineRequire.HtmlReporterV2(j$);
|
||||||
@@ -187,16 +189,52 @@ jasmineRequire.HtmlReporter = function(j$) {
|
|||||||
results.appendChild(summary.rootEl);
|
results.appendChild(summary.rootEl);
|
||||||
|
|
||||||
if (this.#stateBuilder.anyNonTopSuiteFailures) {
|
if (this.#stateBuilder.anyNonTopSuiteFailures) {
|
||||||
this.#alerts.addFailureToggle(
|
this.#addFailureToggle();
|
||||||
() => this.#setMenuModeTo('jasmine-failure-list'),
|
|
||||||
() => this.#setMenuModeTo('jasmine-spec-list')
|
|
||||||
);
|
|
||||||
|
|
||||||
this.#setMenuModeTo('jasmine-failure-list');
|
this.#setMenuModeTo('jasmine-failure-list');
|
||||||
this.#failures.show();
|
this.#failures.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#addFailureToggle() {
|
||||||
|
const onClickFailures = () => this.#setMenuModeTo('jasmine-failure-list');
|
||||||
|
const onClickSpecList = () => this.#setMenuModeTo('jasmine-spec-list');
|
||||||
|
const failuresLink = createDom(
|
||||||
|
'a',
|
||||||
|
{ className: 'jasmine-failures-menu', href: '#' },
|
||||||
|
'Failures'
|
||||||
|
);
|
||||||
|
let specListLink = createDom(
|
||||||
|
'a',
|
||||||
|
{ className: 'jasmine-spec-list-menu', href: '#' },
|
||||||
|
'Spec List'
|
||||||
|
);
|
||||||
|
|
||||||
|
failuresLink.onclick = function() {
|
||||||
|
onClickFailures();
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
specListLink.onclick = function() {
|
||||||
|
onClickSpecList();
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.#alerts.addBar(
|
||||||
|
createDom(
|
||||||
|
'span',
|
||||||
|
{ className: 'jasmine-menu jasmine-bar jasmine-spec-list' },
|
||||||
|
[createDom('span', {}, 'Spec List | '), failuresLink]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
this.#alerts.addBar(
|
||||||
|
createDom(
|
||||||
|
'span',
|
||||||
|
{ className: 'jasmine-menu jasmine-bar jasmine-failure-list' },
|
||||||
|
[specListLink, createDom('span', {}, ' | Failures ')]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#find(selector) {
|
#find(selector) {
|
||||||
return this.#getContainer().querySelector(
|
return this.#getContainer().querySelector(
|
||||||
'.jasmine_html-reporter ' + selector
|
'.jasmine_html-reporter ' + selector
|
||||||
@@ -434,6 +472,7 @@ jasmineRequire.AlertsView = function(j$) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove this once HtmlReporterV2 doesn't use it
|
||||||
addFailureToggle(onClickFailures, onClickSpecList) {
|
addFailureToggle(onClickFailures, onClickSpecList) {
|
||||||
const failuresLink = createDom(
|
const failuresLink = createDom(
|
||||||
'a',
|
'a',
|
||||||
@@ -456,14 +495,20 @@ jasmineRequire.AlertsView = function(j$) {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.#createAndAdd('jasmine-menu jasmine-bar jasmine-spec-list', [
|
this.rootEl.appendChild(
|
||||||
createDom('span', {}, 'Spec List | '),
|
createDom(
|
||||||
failuresLink
|
'span',
|
||||||
]);
|
{ className: 'jasmine-menu jasmine-bar jasmine-spec-list' },
|
||||||
this.#createAndAdd('jasmine-menu jasmine-bar jasmine-failure-list', [
|
[createDom('span', {}, 'Spec List | '), failuresLink]
|
||||||
specListLink,
|
)
|
||||||
createDom('span', {}, ' | Failures ')
|
);
|
||||||
]);
|
this.rootEl.appendChild(
|
||||||
|
createDom(
|
||||||
|
'span',
|
||||||
|
{ className: 'jasmine-menu jasmine-bar jasmine-failure-list' },
|
||||||
|
[specListLink, createDom('span', {}, ' | Failures ')]
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
addGlobalFailure(failure) {
|
addGlobalFailure(failure) {
|
||||||
@@ -946,6 +991,10 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
|
|||||||
|
|
||||||
const { createDom, noExpectations } = j$.private.htmlReporterUtils;
|
const { createDom, noExpectations } = j$.private.htmlReporterUtils;
|
||||||
|
|
||||||
|
const specListTabId = 'jasmine-specListTab';
|
||||||
|
const failuresTabId = 'jasmine-failuresTab';
|
||||||
|
const perfTabId = 'jasmine-perfTab';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class HtmlReporterV2
|
* @class HtmlReporterV2
|
||||||
* @classdesc Displays results and allows re-running individual specs and suites.
|
* @classdesc Displays results and allows re-running individual specs and suites.
|
||||||
@@ -958,7 +1007,7 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
|
|||||||
* const reporter = new jasmine.HtmlReporterV2({
|
* const reporter = new jasmine.HtmlReporterV2({
|
||||||
* env,
|
* env,
|
||||||
* urls,
|
* urls,
|
||||||
* container: document.body
|
* getContainer: () => document.body
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
class HtmlReporterV2 {
|
class HtmlReporterV2 {
|
||||||
@@ -974,6 +1023,7 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
|
|||||||
// Sub-views
|
// Sub-views
|
||||||
#alerts;
|
#alerts;
|
||||||
#statusBar;
|
#statusBar;
|
||||||
|
#tabBar;
|
||||||
#progress;
|
#progress;
|
||||||
#banner;
|
#banner;
|
||||||
#failures;
|
#failures;
|
||||||
@@ -1011,6 +1061,25 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
|
|||||||
this.#statusBar = new j$.private.OverallStatusBar(this.#urlBuilder);
|
this.#statusBar = new j$.private.OverallStatusBar(this.#urlBuilder);
|
||||||
this.#statusBar.showRunning();
|
this.#statusBar.showRunning();
|
||||||
this.#alerts.addBar(this.#statusBar.rootEl);
|
this.#alerts.addBar(this.#statusBar.rootEl);
|
||||||
|
|
||||||
|
this.#tabBar = new j$.private.TabBar(
|
||||||
|
[
|
||||||
|
{ id: specListTabId, label: 'Spec List' },
|
||||||
|
{ id: failuresTabId, label: 'Failures' },
|
||||||
|
{ id: perfTabId, label: 'Performance' }
|
||||||
|
],
|
||||||
|
tabId => {
|
||||||
|
if (tabId === specListTabId) {
|
||||||
|
this.#setMenuModeTo('jasmine-spec-list');
|
||||||
|
} else if (tabId === failuresTabId) {
|
||||||
|
this.#setMenuModeTo('jasmine-failure-list');
|
||||||
|
} else {
|
||||||
|
this.#setMenuModeTo('jasmine-performance');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.#alerts.addBar(this.#tabBar.rootEl);
|
||||||
|
|
||||||
this.#progress = new ProgressView();
|
this.#progress = new ProgressView();
|
||||||
this.#banner = new j$.private.Banner(
|
this.#banner = new j$.private.Banner(
|
||||||
this.#queryString.navigateWithNewParam.bind(this.#queryString),
|
this.#queryString.navigateWithNewParam.bind(this.#queryString),
|
||||||
@@ -1101,15 +1170,17 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
|
|||||||
);
|
);
|
||||||
summary.addResults(this.#stateBuilder.topResults);
|
summary.addResults(this.#stateBuilder.topResults);
|
||||||
results.appendChild(summary.rootEl);
|
results.appendChild(summary.rootEl);
|
||||||
|
const perf = new j$.private.PerformanceView();
|
||||||
|
perf.addResults(this.#stateBuilder.topResults);
|
||||||
|
results.appendChild(perf.rootEl);
|
||||||
|
this.#tabBar.showTab(specListTabId);
|
||||||
|
this.#tabBar.showTab(perfTabId);
|
||||||
|
|
||||||
if (this.#stateBuilder.anyNonTopSuiteFailures) {
|
if (this.#stateBuilder.anyNonTopSuiteFailures) {
|
||||||
this.#alerts.addFailureToggle(
|
this.#tabBar.showTab(failuresTabId);
|
||||||
() => this.#setMenuModeTo('jasmine-failure-list'),
|
this.#tabBar.selectTab(failuresTabId);
|
||||||
() => this.#setMenuModeTo('jasmine-spec-list')
|
} else {
|
||||||
);
|
this.#tabBar.selectTab(specListTabId);
|
||||||
|
|
||||||
this.#setMenuModeTo('jasmine-failure-list');
|
|
||||||
this.#failures.show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1148,7 +1219,6 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
|
|||||||
this.rootEl.value = this.rootEl.value + 1;
|
this.rootEl.value = this.rootEl.value + 1;
|
||||||
|
|
||||||
if (result.status === 'failed') {
|
if (result.status === 'failed') {
|
||||||
// TODO: also a non-color indicator
|
|
||||||
this.rootEl.classList.add('failed');
|
this.rootEl.classList.add('failed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1233,7 +1303,10 @@ jasmineRequire.HtmlReporterV2Urls = function(j$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link Configuration} from the current page's URL.
|
* Creates a {@link Configuration} from the current page's URL. Supported
|
||||||
|
* query string parameters include all those set by {@link HtmlReporterV2}
|
||||||
|
* as well as spec=partialPath, which filters out specs whose paths don't
|
||||||
|
* contain partialPath.
|
||||||
* @returns {Configuration}
|
* @returns {Configuration}
|
||||||
* @example
|
* @example
|
||||||
* const urls = new jasmine.HtmlReporterV2Urls();
|
* const urls = new jasmine.HtmlReporterV2Urls();
|
||||||
@@ -1259,9 +1332,10 @@ jasmineRequire.HtmlReporterV2Urls = function(j$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const specFilter = new j$.private.HtmlSpecFilterV2({
|
const specFilter = new j$.private.HtmlSpecFilterV2({
|
||||||
filterString: () => {
|
filterParams: () => ({
|
||||||
return this.queryString.getParam('path');
|
path: this.queryString.getParam('path'),
|
||||||
}
|
spec: this.queryString.getParam('spec')
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
config.specFilter = function(spec) {
|
config.specFilter = function(spec) {
|
||||||
@@ -1281,35 +1355,35 @@ jasmineRequire.HtmlReporterV2Urls = function(j$) {
|
|||||||
|
|
||||||
jasmineRequire.HtmlSpecFilterV2 = function() {
|
jasmineRequire.HtmlSpecFilterV2 = function() {
|
||||||
class HtmlSpecFilterV2 {
|
class HtmlSpecFilterV2 {
|
||||||
#getFilterString;
|
#getFilterParams;
|
||||||
|
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
this.#getFilterString = options.filterString;
|
this.#getFilterParams = options.filterParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines whether the spec with the specified name should be executed.
|
|
||||||
* @name HtmlSpecFilterV2#matches
|
|
||||||
* @function
|
|
||||||
* @param {Spec} spec
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
matches(spec) {
|
matches(spec) {
|
||||||
const filterString = this.#getFilterString();
|
const params = this.#getFilterParams();
|
||||||
|
|
||||||
if (!filterString) {
|
if (params.path) {
|
||||||
return true;
|
return this.#matchesPath(spec, JSON.parse(params.path));
|
||||||
|
} else if (params.spec) {
|
||||||
|
// Like legacy HtmlSpecFilter, retained because it's convenient for
|
||||||
|
// hand-constructing filter URLs
|
||||||
|
return spec.getFullName().includes(params.spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterPath = JSON.parse(this.#getFilterString());
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#matchesPath(spec, path) {
|
||||||
const specPath = spec.getPath();
|
const specPath = spec.getPath();
|
||||||
|
|
||||||
if (filterPath.length > specPath.length) {
|
if (path.length > specPath.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < filterPath.length; i++) {
|
for (let i = 0; i < path.length; i++) {
|
||||||
if (specPath[i] !== filterPath[i]) {
|
if (specPath[i] !== path[i]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1430,6 +1504,105 @@ jasmineRequire.OverallStatusBar = function(j$) {
|
|||||||
return OverallStatusBar;
|
return OverallStatusBar;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
jasmineRequire.PerformanceView = function(j$) {
|
||||||
|
const createDom = j$.private.htmlReporterUtils.createDom;
|
||||||
|
const MAX_SLOW_SPECS = 20;
|
||||||
|
|
||||||
|
class PerformanceView {
|
||||||
|
#summary;
|
||||||
|
#tbody;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.#tbody = document.createElement('tbody');
|
||||||
|
this.#summary = document.createElement('div');
|
||||||
|
this.rootEl = createDom(
|
||||||
|
'div',
|
||||||
|
{ className: 'jasmine-performance-view' },
|
||||||
|
createDom('h2', {}, 'Performance'),
|
||||||
|
this.#summary,
|
||||||
|
createDom('h3', {}, 'Slowest Specs'),
|
||||||
|
createDom(
|
||||||
|
'table',
|
||||||
|
{},
|
||||||
|
createDom(
|
||||||
|
'thead',
|
||||||
|
{},
|
||||||
|
createDom(
|
||||||
|
'tr',
|
||||||
|
{},
|
||||||
|
createDom('th', {}, 'Duration'),
|
||||||
|
createDom('th', {}, 'Spec Name')
|
||||||
|
)
|
||||||
|
),
|
||||||
|
this.#tbody
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
addResults(resultsTree) {
|
||||||
|
const specResults = [];
|
||||||
|
getSpecResults(resultsTree, specResults);
|
||||||
|
|
||||||
|
if (specResults.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
specResults.sort(function(a, b) {
|
||||||
|
if (a.duration < b.duration) {
|
||||||
|
return 1;
|
||||||
|
} else if (a.duration > b.duration) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.#populateSumary(specResults);
|
||||||
|
this.#populateTable(specResults);
|
||||||
|
}
|
||||||
|
|
||||||
|
#populateSumary(specResults) {
|
||||||
|
const total = specResults.map(r => r.duration).reduce((a, b) => a + b, 0);
|
||||||
|
const mean = total / specResults.length;
|
||||||
|
const median = specResults[Math.floor(specResults.length / 2)].duration;
|
||||||
|
this.#summary.appendChild(
|
||||||
|
document.createTextNode(`Mean spec run time: ${mean.toFixed(0)}ms`)
|
||||||
|
);
|
||||||
|
this.#summary.appendChild(document.createElement('br'));
|
||||||
|
this.#summary.appendChild(
|
||||||
|
document.createTextNode(`Median spec run time: ${median}ms`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#populateTable(specResults) {
|
||||||
|
specResults = specResults.slice(0, MAX_SLOW_SPECS);
|
||||||
|
|
||||||
|
for (const r of specResults) {
|
||||||
|
this.#tbody.appendChild(
|
||||||
|
createDom(
|
||||||
|
'tr',
|
||||||
|
{},
|
||||||
|
createDom('td', {}, `${r.duration}ms`),
|
||||||
|
createDom('td', {}, r.fullName)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSpecResults(resultsTree, dest) {
|
||||||
|
for (const node of resultsTree.children) {
|
||||||
|
if (node.type === 'suite') {
|
||||||
|
getSpecResults(node, dest);
|
||||||
|
} else if (node.result.status !== 'excluded') {
|
||||||
|
dest.push(node.result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PerformanceView;
|
||||||
|
};
|
||||||
|
|
||||||
jasmineRequire.ResultsStateBuilder = function(j$) {
|
jasmineRequire.ResultsStateBuilder = function(j$) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@@ -1661,3 +1834,81 @@ jasmineRequire.SymbolsView = function(j$) {
|
|||||||
|
|
||||||
return SymbolsView;
|
return SymbolsView;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
jasmineRequire.TabBar = function(j$) {
|
||||||
|
const createDom = j$.private.htmlReporterUtils.createDom;
|
||||||
|
|
||||||
|
class TabBar {
|
||||||
|
#tabs;
|
||||||
|
#onSelectTab;
|
||||||
|
|
||||||
|
// tabSpecs should be an array of {id, label}.
|
||||||
|
// All tabs are initially not visible and not selected.
|
||||||
|
constructor(tabSpecs, onSelectTab) {
|
||||||
|
this.#onSelectTab = onSelectTab;
|
||||||
|
this.#tabs = [];
|
||||||
|
this.#tabs = tabSpecs.map(ts => new Tab(ts, () => this.selectTab(ts.id)));
|
||||||
|
|
||||||
|
this.rootEl = createDom(
|
||||||
|
'span',
|
||||||
|
{ className: 'jasmine-menu jasmine-bar' },
|
||||||
|
this.#tabs.map(t => t.rootEl)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
showTab(id) {
|
||||||
|
for (const tab of this.#tabs) {
|
||||||
|
if (tab.rootEl.id === id) {
|
||||||
|
tab.setVisibility(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selectTab(id) {
|
||||||
|
for (const tab of this.#tabs) {
|
||||||
|
tab.setSelected(tab.rootEl.id === id);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#onSelectTab(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Tab {
|
||||||
|
#spec;
|
||||||
|
#onClick;
|
||||||
|
|
||||||
|
constructor(spec, onClick) {
|
||||||
|
this.#spec = spec;
|
||||||
|
this.#onClick = onClick;
|
||||||
|
this.rootEl = createDom(
|
||||||
|
'span',
|
||||||
|
{ id: spec.id, className: 'jasmine-tab jasmine-hidden' },
|
||||||
|
this.#createLink()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
setVisibility(visible) {
|
||||||
|
this.rootEl.classList.toggle('jasmine-hidden', !visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
setSelected(selected) {
|
||||||
|
if (selected) {
|
||||||
|
this.rootEl.textContent = this.#spec.label;
|
||||||
|
} else {
|
||||||
|
this.rootEl.textContent = '';
|
||||||
|
this.rootEl.appendChild(this.#createLink());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#createLink() {
|
||||||
|
const link = createDom('a', { href: '#' }, this.#spec.label);
|
||||||
|
link.addEventListener('click', e => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.#onClick();
|
||||||
|
});
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TabBar;
|
||||||
|
};
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ body {
|
|||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
margin: -8px;
|
margin: -8px;
|
||||||
font-size: 11px;
|
font-size: 12px;
|
||||||
font-family: Monaco, "Lucida Console", monospace;
|
font-family: Monaco, "Lucida Console", monospace;
|
||||||
line-height: 14px;
|
line-height: 14px;
|
||||||
color: #333;
|
color: #333;
|
||||||
@@ -63,7 +63,7 @@ body {
|
|||||||
float: right;
|
float: right;
|
||||||
line-height: 28px;
|
line-height: 28px;
|
||||||
padding-right: 9px;
|
padding-right: 9px;
|
||||||
font-size: 11px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
.jasmine_html-reporter .jasmine-symbol-summary {
|
.jasmine_html-reporter .jasmine-symbol-summary {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -198,11 +198,17 @@ body {
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
.jasmine_html-reporter.jasmine-spec-list .jasmine-bar.jasmine-menu.jasmine-failure-list,
|
.jasmine_html-reporter.jasmine-spec-list .jasmine-bar.jasmine-menu.jasmine-failure-list,
|
||||||
.jasmine_html-reporter.jasmine-spec-list .jasmine-results .jasmine-failures {
|
.jasmine_html-reporter.jasmine-spec-list .jasmine-results .jasmine-failures,
|
||||||
|
.jasmine_html-reporter.jasmine-spec-list .jasmine-performance-view {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.jasmine_html-reporter.jasmine-failure-list .jasmine-bar.jasmine-menu.jasmine-spec-list,
|
.jasmine_html-reporter.jasmine-failure-list .jasmine-bar.jasmine-menu.jasmine-spec-list,
|
||||||
.jasmine_html-reporter.jasmine-failure-list .jasmine-summary {
|
.jasmine_html-reporter.jasmine-failure-list .jasmine-summary,
|
||||||
|
.jasmine_html-reporter.jasmine-failure-list .jasmine-performance-view {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.jasmine_html-reporter.jasmine-performance .jasmine-results .jasmine-failures,
|
||||||
|
.jasmine_html-reporter.jasmine-performance .jasmine-summary {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.jasmine_html-reporter .jasmine-results {
|
.jasmine_html-reporter .jasmine-results {
|
||||||
@@ -323,4 +329,23 @@ body {
|
|||||||
}
|
}
|
||||||
.jasmine_html-reporter .jasmine-debug-log .jasmine-debug-log-msg {
|
.jasmine_html-reporter .jasmine-debug-log .jasmine-debug-log-msg {
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jasmine-hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jasmine-tab + .jasmine-tab:before {
|
||||||
|
content: " | ";
|
||||||
|
}
|
||||||
|
|
||||||
|
.jasmine-performance-view h2, .jasmine-performance-view h3 {
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
.jasmine-performance-view table {
|
||||||
|
border-spacing: 5px;
|
||||||
|
}
|
||||||
|
.jasmine-performance-view th, .jasmine-performance-view td {
|
||||||
|
text-align: left;
|
||||||
}
|
}
|
||||||
+342
-158
@@ -50,11 +50,12 @@ var getJasmineRequireObj = (function() {
|
|||||||
j$.private.util = jRequire.util(j$);
|
j$.private.util = jRequire.util(j$);
|
||||||
j$.private.errors = jRequire.errors();
|
j$.private.errors = jRequire.errors();
|
||||||
j$.private.formatErrorMsg = jRequire.formatErrorMsg(j$);
|
j$.private.formatErrorMsg = jRequire.formatErrorMsg(j$);
|
||||||
|
j$.private.AllOf = jRequire.AllOf(j$);
|
||||||
j$.private.Any = jRequire.Any(j$);
|
j$.private.Any = jRequire.Any(j$);
|
||||||
j$.private.Anything = jRequire.Anything(j$);
|
j$.private.Anything = jRequire.Anything(j$);
|
||||||
j$.private.CallTracker = jRequire.CallTracker(j$);
|
j$.private.CallTracker = jRequire.CallTracker(j$);
|
||||||
j$.private.MockDate = jRequire.MockDate(j$);
|
j$.private.MockDate = jRequire.MockDate(j$);
|
||||||
j$.private.getClearStack = jRequire.clearStack(j$);
|
j$.private.getStackClearer = jRequire.StackClearer(j$);
|
||||||
j$.private.Clock = jRequire.Clock();
|
j$.private.Clock = jRequire.Clock();
|
||||||
j$.private.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$);
|
j$.private.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$);
|
||||||
j$.private.Deprecator = jRequire.Deprecator(j$);
|
j$.private.Deprecator = jRequire.Deprecator(j$);
|
||||||
@@ -407,6 +408,19 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||||
|
* value being compared matches every provided equality tester.
|
||||||
|
* @name asymmetricEqualityTesters.allOf
|
||||||
|
* @emittedName jasmine.allOf
|
||||||
|
* @since 5.13.0
|
||||||
|
* @function
|
||||||
|
* @param {...*} arguments - The asymmetric equality checkers to compare.
|
||||||
|
*/
|
||||||
|
j$.allOf = function() {
|
||||||
|
return new j$.AllOf(...arguments);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||||
* value being compared is an instance of the specified class/constructor.
|
* value being compared is an instance of the specified class/constructor.
|
||||||
@@ -849,8 +863,11 @@ getJasmineRequireObj().Spec = function(j$) {
|
|||||||
// Key and value will eventually be cloned during reporting. The error
|
// Key and value will eventually be cloned during reporting. The error
|
||||||
// thrown at that point if they aren't cloneable isn't very helpful.
|
// thrown at that point if they aren't cloneable isn't very helpful.
|
||||||
// Throw a better one now.
|
// Throw a better one now.
|
||||||
j$.private.util.assertReporterCloneable(key, 'Key');
|
if (!j$.private.isString(key)) {
|
||||||
|
throw new Error('Key must be a string');
|
||||||
|
}
|
||||||
j$.private.util.assertReporterCloneable(value, 'Value');
|
j$.private.util.assertReporterCloneable(value, 'Value');
|
||||||
|
|
||||||
this.#executionState.properties = this.#executionState.properties || {};
|
this.#executionState.properties = this.#executionState.properties || {};
|
||||||
this.#executionState.properties[key] = value;
|
this.#executionState.properties[key] = value;
|
||||||
}
|
}
|
||||||
@@ -930,12 +947,11 @@ getJasmineRequireObj().Spec = function(j$) {
|
|||||||
* @property {String} description - The description passed to the {@link it} that created this spec.
|
* @property {String} description - The description passed to the {@link it} that created this spec.
|
||||||
* @property {String} fullName - The full description including all ancestors of this spec.
|
* @property {String} fullName - The full description including all ancestors of this spec.
|
||||||
* @property {String|null} parentSuiteId - The ID of the suite containing this spec, or null if this spec is not in a describe().
|
* @property {String|null} parentSuiteId - The ID of the suite containing this spec, or null if this spec is not in a describe().
|
||||||
* @property {String} filename - Deprecated. The name of the file the spec was defined in.
|
* @property {String} filename - The name of the file the spec was defined in.
|
||||||
* Note: The value may be incorrect if zone.js is installed or
|
* Note: The value may be incorrect if zone.js is installed or
|
||||||
* `it`/`fit`/`xit` have been replaced with versions that don't maintain the
|
* `it`/`fit`/`xit` have been replaced with versions that don't maintain the
|
||||||
* same call stack height as the originals. This property may be removed in
|
* same call stack height as the originals. You can fix that by setting
|
||||||
* a future version unless there is enough user interest in keeping it.
|
* {@link Configuration#extraItStackFrames}.
|
||||||
* See {@link https://github.com/jasmine/jasmine/issues/2065}.
|
|
||||||
* @property {ExpectationResult[]} failedExpectations - The list of expectations that failed during execution of this spec.
|
* @property {ExpectationResult[]} failedExpectations - The list of expectations that failed during execution of this spec.
|
||||||
* @property {ExpectationResult[]} passedExpectations - The list of expectations that passed during execution of this spec.
|
* @property {ExpectationResult[]} passedExpectations - The list of expectations that passed during execution of this spec.
|
||||||
* @property {ExpectationResult[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec.
|
* @property {ExpectationResult[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec.
|
||||||
@@ -1117,7 +1133,20 @@ getJasmineRequireObj().Spec = function(j$) {
|
|||||||
* @returns {Array.<string>}
|
* @returns {Array.<string>}
|
||||||
* @since 5.7.0
|
* @since 5.7.0
|
||||||
*/
|
*/
|
||||||
getPath: this.getPath.bind(this)
|
getPath: this.getPath.bind(this),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the file the spec was defined in.
|
||||||
|
* Note: The value may be incorrect if zone.js is installed or
|
||||||
|
* `it`/`fit`/`xit` have been replaced with versions that don't maintain the
|
||||||
|
* same call stack height as the originals. You can fix that by setting
|
||||||
|
* {@link Configuration#extraItStackFrames}.
|
||||||
|
* @name Spec#filename
|
||||||
|
* @readonly
|
||||||
|
* @type {string}
|
||||||
|
* @since 5.13.0
|
||||||
|
*/
|
||||||
|
filename: this.filename
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1196,6 +1225,8 @@ getJasmineRequireObj().Order = function() {
|
|||||||
getJasmineRequireObj().Env = function(j$) {
|
getJasmineRequireObj().Env = function(j$) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const DEFAULT_IT_DESCRIBE_STACK_DEPTH = 3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class Env
|
* @class Env
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
@@ -1213,7 +1244,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
|
|
||||||
const realSetTimeout = global.setTimeout;
|
const realSetTimeout = global.setTimeout;
|
||||||
const realClearTimeout = global.clearTimeout;
|
const realClearTimeout = global.clearTimeout;
|
||||||
const clearStack = j$.private.getClearStack(global);
|
const stackClearer = j$.private.getStackClearer(global);
|
||||||
this.clock = new j$.private.Clock(
|
this.clock = new j$.private.Clock(
|
||||||
global,
|
global,
|
||||||
function() {
|
function() {
|
||||||
@@ -1223,7 +1254,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const globalErrors = new GlobalErrors(
|
const globalErrors = new GlobalErrors(
|
||||||
undefined,
|
global,
|
||||||
// Configuration is late-bound because GlobalErrors needs to be constructed
|
// Configuration is late-bound because GlobalErrors needs to be constructed
|
||||||
// before it's set to detect load-time errors in browsers
|
// before it's set to detect load-time errors in browsers
|
||||||
() => this.configuration()
|
() => this.configuration()
|
||||||
@@ -1292,6 +1323,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
|
|
||||||
config.update(changes);
|
config.update(changes);
|
||||||
deprecator.verboseDeprecations(config.verboseDeprecations);
|
deprecator.verboseDeprecations(config.verboseDeprecations);
|
||||||
|
stackClearer.setSafariYieldStrategy(config.safariYieldStrategy);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1494,7 +1526,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function runQueue(options) {
|
function runQueue(options) {
|
||||||
options.clearStack = options.clearStack || clearStack;
|
options.clearStack = options.clearStack || stackClearer;
|
||||||
options.timeout = {
|
options.timeout = {
|
||||||
setTimeout: realSetTimeout,
|
setTimeout: realSetTimeout,
|
||||||
clearTimeout: realClearTimeout
|
clearTimeout: realClearTimeout
|
||||||
@@ -1786,14 +1818,14 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
|
|
||||||
this.describe = function(description, definitionFn) {
|
this.describe = function(description, definitionFn) {
|
||||||
ensureIsNotNested('describe');
|
ensureIsNotNested('describe');
|
||||||
const filename = callerCallerFilename();
|
const filename = indirectCallerFilename(describeStackDepth());
|
||||||
return suiteBuilder.describe(description, definitionFn, filename)
|
return suiteBuilder.describe(description, definitionFn, filename)
|
||||||
.metadata;
|
.metadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.xdescribe = function(description, definitionFn) {
|
this.xdescribe = function(description, definitionFn) {
|
||||||
ensureIsNotNested('xdescribe');
|
ensureIsNotNested('xdescribe');
|
||||||
const filename = callerCallerFilename();
|
const filename = indirectCallerFilename(describeStackDepth());
|
||||||
return suiteBuilder.xdescribe(description, definitionFn, filename)
|
return suiteBuilder.xdescribe(description, definitionFn, filename)
|
||||||
.metadata;
|
.metadata;
|
||||||
};
|
};
|
||||||
@@ -1801,30 +1833,38 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
this.fdescribe = function(description, definitionFn) {
|
this.fdescribe = function(description, definitionFn) {
|
||||||
ensureIsNotNested('fdescribe');
|
ensureIsNotNested('fdescribe');
|
||||||
ensureNonParallel('fdescribe');
|
ensureNonParallel('fdescribe');
|
||||||
const filename = callerCallerFilename();
|
const filename = indirectCallerFilename(describeStackDepth());
|
||||||
return suiteBuilder.fdescribe(description, definitionFn, filename)
|
return suiteBuilder.fdescribe(description, definitionFn, filename)
|
||||||
.metadata;
|
.metadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.it = function(description, fn, timeout) {
|
this.it = function(description, fn, timeout) {
|
||||||
ensureIsNotNested('it');
|
ensureIsNotNested('it');
|
||||||
const filename = callerCallerFilename();
|
const filename = indirectCallerFilename(itStackDepth());
|
||||||
return suiteBuilder.it(description, fn, timeout, filename).metadata;
|
return suiteBuilder.it(description, fn, timeout, filename).metadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.xit = function(description, fn, timeout) {
|
this.xit = function(description, fn, timeout) {
|
||||||
ensureIsNotNested('xit');
|
ensureIsNotNested('xit');
|
||||||
const filename = callerCallerFilename();
|
const filename = indirectCallerFilename(itStackDepth());
|
||||||
return suiteBuilder.xit(description, fn, timeout, filename).metadata;
|
return suiteBuilder.xit(description, fn, timeout, filename).metadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.fit = function(description, fn, timeout) {
|
this.fit = function(description, fn, timeout) {
|
||||||
ensureIsNotNested('fit');
|
ensureIsNotNested('fit');
|
||||||
ensureNonParallel('fit');
|
ensureNonParallel('fit');
|
||||||
const filename = callerCallerFilename();
|
const filename = indirectCallerFilename(itStackDepth());
|
||||||
return suiteBuilder.fit(description, fn, timeout, filename).metadata;
|
return suiteBuilder.fit(description, fn, timeout, filename).metadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function itStackDepth() {
|
||||||
|
return DEFAULT_IT_DESCRIBE_STACK_DEPTH + config.extraItStackFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
function describeStackDepth() {
|
||||||
|
return DEFAULT_IT_DESCRIBE_STACK_DEPTH + config.extraDescribeStackFrames;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a user-defined property as part of the properties field of {@link SpecDoneEvent}
|
* Get a user-defined property as part of the properties field of {@link SpecDoneEvent}
|
||||||
* @name Env#getSpecProperty
|
* @name Env#getSpecProperty
|
||||||
@@ -2010,11 +2050,12 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function callerCallerFilename() {
|
function indirectCallerFilename(depth) {
|
||||||
const frames = new j$.private.StackTrace(new Error()).frames;
|
const frames = new j$.private.StackTrace(new Error()).frames;
|
||||||
// frames[3] should always exist except in Jasmine's own tests, which bypass
|
// The specified frame should always exist except in Jasmine's own tests,
|
||||||
// the global it/describe layer, but don't crash if it doesn't.
|
// which bypass the global it/describe layer, but could be absent in case
|
||||||
return frames[3] && frames[3].file;
|
// of misconfiguration. Don't crash if it's absent.
|
||||||
|
return frames[depth] && frames[depth].file;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Env;
|
return Env;
|
||||||
@@ -2152,6 +2193,36 @@ getJasmineRequireObj().JsApiReporter = function(j$) {
|
|||||||
return JsApiReporter;
|
return JsApiReporter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
getJasmineRequireObj().AllOf = function(j$) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function AllOf() {
|
||||||
|
const expectedValues = Array.from(arguments);
|
||||||
|
if (expectedValues.length === 0) {
|
||||||
|
throw new TypeError(
|
||||||
|
'jasmine.allOf() expects at least one argument to be passed.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.expectedValues = expectedValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
AllOf.prototype.asymmetricMatch = function(other, matchersUtil) {
|
||||||
|
for (const expectedValue of this.expectedValues) {
|
||||||
|
if (!matchersUtil.equals(other, expectedValue)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
AllOf.prototype.jasmineToString = function(pp) {
|
||||||
|
return '<jasmine.allOf(' + pp(this.expectedValues) + ')>';
|
||||||
|
};
|
||||||
|
|
||||||
|
return AllOf;
|
||||||
|
};
|
||||||
|
|
||||||
getJasmineRequireObj().Any = function(j$) {
|
getJasmineRequireObj().Any = function(j$) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@@ -2849,131 +2920,6 @@ getJasmineRequireObj().CallTracker = function(j$) {
|
|||||||
return CallTracker;
|
return CallTracker;
|
||||||
};
|
};
|
||||||
|
|
||||||
getJasmineRequireObj().clearStack = function(j$) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const maxInlineCallCount = 10;
|
|
||||||
|
|
||||||
function browserQueueMicrotaskImpl(global) {
|
|
||||||
const unclampedSetTimeout = getUnclampedSetTimeout(global);
|
|
||||||
const { queueMicrotask } = global;
|
|
||||||
let currentCallCount = 0;
|
|
||||||
return function clearStack(fn) {
|
|
||||||
currentCallCount++;
|
|
||||||
|
|
||||||
if (currentCallCount < maxInlineCallCount) {
|
|
||||||
queueMicrotask(fn);
|
|
||||||
} else {
|
|
||||||
currentCallCount = 0;
|
|
||||||
unclampedSetTimeout(fn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function nodeQueueMicrotaskImpl(global) {
|
|
||||||
const { queueMicrotask } = global;
|
|
||||||
|
|
||||||
return function(fn) {
|
|
||||||
queueMicrotask(fn);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function messageChannelImpl(global) {
|
|
||||||
const { setTimeout } = global;
|
|
||||||
const postMessage = getPostMessage(global);
|
|
||||||
|
|
||||||
let currentCallCount = 0;
|
|
||||||
return function clearStack(fn) {
|
|
||||||
currentCallCount++;
|
|
||||||
|
|
||||||
if (currentCallCount < maxInlineCallCount) {
|
|
||||||
postMessage(fn);
|
|
||||||
} else {
|
|
||||||
currentCallCount = 0;
|
|
||||||
setTimeout(fn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUnclampedSetTimeout(global) {
|
|
||||||
const { setTimeout } = global;
|
|
||||||
if (!global.MessageChannel) {
|
|
||||||
return setTimeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
const postMessage = getPostMessage(global);
|
|
||||||
return function unclampedSetTimeout(fn) {
|
|
||||||
postMessage(function() {
|
|
||||||
setTimeout(fn);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPostMessage(global) {
|
|
||||||
const { MessageChannel, setTimeout } = global;
|
|
||||||
const channel = new MessageChannel();
|
|
||||||
let head = {};
|
|
||||||
let tail = head;
|
|
||||||
|
|
||||||
let taskRunning = false;
|
|
||||||
channel.port1.onmessage = function() {
|
|
||||||
head = head.next;
|
|
||||||
const task = head.task;
|
|
||||||
delete head.task;
|
|
||||||
|
|
||||||
if (taskRunning) {
|
|
||||||
setTimeout(task, 0);
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
taskRunning = true;
|
|
||||||
task();
|
|
||||||
} finally {
|
|
||||||
taskRunning = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return function postMessage(fn) {
|
|
||||||
tail = tail.next = { task: fn };
|
|
||||||
channel.port2.postMessage(0);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getClearStack(global) {
|
|
||||||
const NODE_JS =
|
|
||||||
global.process &&
|
|
||||||
global.process.versions &&
|
|
||||||
typeof global.process.versions.node === 'string';
|
|
||||||
|
|
||||||
// Windows builds of WebKit have a fairly generic user agent string when no application name is provided:
|
|
||||||
// e.g. "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko)"
|
|
||||||
const SAFARI_OR_WIN_WEBKIT =
|
|
||||||
global.navigator &&
|
|
||||||
/(^((?!chrome|android).)*safari)|(Win64; x64\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\)$)/i.test(
|
|
||||||
global.navigator.userAgent
|
|
||||||
);
|
|
||||||
|
|
||||||
if (NODE_JS) {
|
|
||||||
// Unlike browsers, Node doesn't require us to do a periodic setTimeout
|
|
||||||
// so we avoid the overhead.
|
|
||||||
return nodeQueueMicrotaskImpl(global);
|
|
||||||
} else if (SAFARI_OR_WIN_WEBKIT || !global.MessageChannel /* tests */) {
|
|
||||||
// queueMicrotask is dramatically faster than MessageChannel in Safari
|
|
||||||
// and other WebKit-based browsers, such as the one distributed by Playwright
|
|
||||||
// to test Safari-like behavior on Windows.
|
|
||||||
// Some of our own integration tests provide a mock queueMicrotask in all
|
|
||||||
// environments because it's simpler to mock than MessageChannel.
|
|
||||||
return browserQueueMicrotaskImpl(global);
|
|
||||||
} else {
|
|
||||||
// MessageChannel is faster than queueMicrotask in supported browsers
|
|
||||||
// other than Safari.
|
|
||||||
return messageChannelImpl(global);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return getClearStack;
|
|
||||||
};
|
|
||||||
|
|
||||||
getJasmineRequireObj().Clock = function() {
|
getJasmineRequireObj().Clock = function() {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@@ -3507,7 +3453,45 @@ getJasmineRequireObj().Configuration = function(j$) {
|
|||||||
* @type Boolean
|
* @type Boolean
|
||||||
* @default false
|
* @default false
|
||||||
*/
|
*/
|
||||||
detectLateRejectionHandling: false
|
detectLateRejectionHandling: false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of extra stack frames inserted by a wrapper around {@link it}
|
||||||
|
* or by some other local modification. Jasmine uses this to determine the
|
||||||
|
* filename for {@link SpecStartedEvent} and {@link SpecDoneEvent}.
|
||||||
|
* @name Configuration#extraItStackFrames
|
||||||
|
* @since 5.13.0
|
||||||
|
* @type number
|
||||||
|
* @default 0
|
||||||
|
*/
|
||||||
|
extraItStackFrames: 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of extra stack frames inserted by a wrapper around
|
||||||
|
* {@link describe} or by some other local modification. Jasmine uses this
|
||||||
|
* to determine the filename for {@link SpecStartedEvent} and
|
||||||
|
* {@link SpecDoneEvent}.
|
||||||
|
* @name Configuration#extraDescribeStackFrames
|
||||||
|
* @since 5.13.0
|
||||||
|
* @type number
|
||||||
|
* @default 0
|
||||||
|
*/
|
||||||
|
extraDescribeStackFrames: 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The strategy to use in Safari and similar browsers to determine how often
|
||||||
|
* to yield control by calling setTimeout. If set to "count", the default,
|
||||||
|
* the frequency of setTimeout calls is based on the number of relevant
|
||||||
|
* function calls. If set to "time", the frequency of setTimeout calls is
|
||||||
|
* based on elapsed time. Using "time" may provide a significant performance
|
||||||
|
* improvement, but as of 6.0 it hasn't been tested with a wide variety of
|
||||||
|
* workloads and should be considered experimental.
|
||||||
|
* @name Configuration#safariYieldStrategy
|
||||||
|
* @since 6.0.0
|
||||||
|
* @type 'count' | 'time'
|
||||||
|
* @default 'count'
|
||||||
|
*/
|
||||||
|
safariYieldStrategy: 'count'
|
||||||
};
|
};
|
||||||
Object.freeze(defaultConfig);
|
Object.freeze(defaultConfig);
|
||||||
|
|
||||||
@@ -3558,6 +3542,28 @@ getJasmineRequireObj().Configuration = function(j$) {
|
|||||||
if (typeof changes.seed !== 'undefined') {
|
if (typeof changes.seed !== 'undefined') {
|
||||||
this.#values.seed = changes.seed;
|
this.#values.seed = changes.seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 0 is a valid value for both of these, so a truthiness check wouldn't work
|
||||||
|
if (typeof changes.extraItStackFrames !== 'undefined') {
|
||||||
|
this.#values.extraItStackFrames = changes.extraItStackFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof changes.extraDescribeStackFrames !== 'undefined') {
|
||||||
|
this.#values.extraDescribeStackFrames =
|
||||||
|
changes.extraDescribeStackFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof changes.safariYieldStrategy !== 'undefined') {
|
||||||
|
const v = changes.safariYieldStrategy;
|
||||||
|
|
||||||
|
if (v === 'count' || v === 'time') {
|
||||||
|
this.#values.safariYieldStrategy = v;
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
"Invalid safariYieldStrategy value. Valid values are 'count' and 'time'."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8560,11 +8566,11 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.onComplete = attrs.onComplete || emptyFn;
|
this.onComplete = attrs.onComplete || emptyFn;
|
||||||
this.clearStack =
|
this.clearStack = attrs.clearStack || {
|
||||||
attrs.clearStack ||
|
clearStack(fn) {
|
||||||
function(fn) {
|
|
||||||
fn();
|
fn();
|
||||||
};
|
}
|
||||||
|
};
|
||||||
this.onException = attrs.onException || emptyFn;
|
this.onException = attrs.onException || emptyFn;
|
||||||
this.onMultipleDone = attrs.onMultipleDone || fallbackOnMultipleDone;
|
this.onMultipleDone = attrs.onMultipleDone || fallbackOnMultipleDone;
|
||||||
this.userContext = attrs.userContext || new j$.private.UserContext();
|
this.userContext = attrs.userContext || new j$.private.UserContext();
|
||||||
@@ -8744,7 +8750,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.clearStack(() => {
|
this.clearStack.clearStack(() => {
|
||||||
this.globalErrors.popListener(this.handleFinalError);
|
this.globalErrors.popListener(this.handleFinalError);
|
||||||
|
|
||||||
if (this.errored_) {
|
if (this.errored_) {
|
||||||
@@ -8902,6 +8908,7 @@ getJasmineRequireObj().reporterEvents = function(j$) {
|
|||||||
* {@link ReporterCapabilities} will apply.
|
* {@link ReporterCapabilities} will apply.
|
||||||
* @name Reporter#reporterCapabilities
|
* @name Reporter#reporterCapabilities
|
||||||
* @type ReporterCapabilities | undefined
|
* @type ReporterCapabilities | undefined
|
||||||
|
* @optional
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
@@ -8968,6 +8975,7 @@ getJasmineRequireObj().reporterEvents = function(j$) {
|
|||||||
/**
|
/**
|
||||||
* `specStarted` is invoked when an `it` starts to run (including associated `beforeEach` functions)
|
* `specStarted` is invoked when an `it` starts to run (including associated `beforeEach` functions)
|
||||||
* @function
|
* @function
|
||||||
|
* @optional
|
||||||
* @name Reporter#specStarted
|
* @name Reporter#specStarted
|
||||||
* @param {SpecStartedEvent} result Information about the individual {@link it} being run
|
* @param {SpecStartedEvent} result Information about the individual {@link it} being run
|
||||||
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
||||||
@@ -10678,6 +10686,164 @@ getJasmineRequireObj().SpyStrategy = function(j$) {
|
|||||||
return SpyStrategy;
|
return SpyStrategy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
getJasmineRequireObj().StackClearer = function(j$) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const maxInlineCallCount = 10;
|
||||||
|
// 25ms gives a good balance of speed and UI responsiveness when running
|
||||||
|
// jasmine-core's own tests in Safari 18. The exact value isn't critical.
|
||||||
|
const safariYieldIntervalMs = 25;
|
||||||
|
|
||||||
|
function browserQueueMicrotaskImpl(global) {
|
||||||
|
const unclampedSetTimeout = getUnclampedSetTimeout(global);
|
||||||
|
const { queueMicrotask } = global;
|
||||||
|
let yieldStrategy = 'count';
|
||||||
|
let currentCallCount = 0; // for count strategy
|
||||||
|
let nextSetTimeoutTime; // for time strategy
|
||||||
|
|
||||||
|
return {
|
||||||
|
clearStack(fn) {
|
||||||
|
currentCallCount++;
|
||||||
|
let shouldSetTimeout;
|
||||||
|
|
||||||
|
if (yieldStrategy === 'time') {
|
||||||
|
const now = new Date().getTime();
|
||||||
|
shouldSetTimeout = now >= nextSetTimeoutTime;
|
||||||
|
if (shouldSetTimeout) {
|
||||||
|
nextSetTimeoutTime = now + safariYieldIntervalMs;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
shouldSetTimeout = currentCallCount >= maxInlineCallCount;
|
||||||
|
if (shouldSetTimeout) {
|
||||||
|
currentCallCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldSetTimeout) {
|
||||||
|
unclampedSetTimeout(fn);
|
||||||
|
} else {
|
||||||
|
queueMicrotask(fn);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setSafariYieldStrategy(strategy) {
|
||||||
|
yieldStrategy = strategy;
|
||||||
|
|
||||||
|
if (yieldStrategy === 'time') {
|
||||||
|
nextSetTimeoutTime = new Date().getTime() + safariYieldIntervalMs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function nodeQueueMicrotaskImpl(global) {
|
||||||
|
const { queueMicrotask } = global;
|
||||||
|
|
||||||
|
return {
|
||||||
|
clearStack(fn) {
|
||||||
|
queueMicrotask(fn);
|
||||||
|
},
|
||||||
|
setSafariYieldStrategy() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function messageChannelImpl(global) {
|
||||||
|
const { setTimeout } = global;
|
||||||
|
const postMessage = getPostMessage(global);
|
||||||
|
|
||||||
|
let currentCallCount = 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
clearStack(fn) {
|
||||||
|
currentCallCount++;
|
||||||
|
|
||||||
|
if (currentCallCount < maxInlineCallCount) {
|
||||||
|
postMessage(fn);
|
||||||
|
} else {
|
||||||
|
currentCallCount = 0;
|
||||||
|
setTimeout(fn);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setSafariYieldStrategy() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUnclampedSetTimeout(global) {
|
||||||
|
const { setTimeout } = global;
|
||||||
|
if (!global.MessageChannel) {
|
||||||
|
return setTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
const postMessage = getPostMessage(global);
|
||||||
|
return function unclampedSetTimeout(fn) {
|
||||||
|
postMessage(function() {
|
||||||
|
setTimeout(fn);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPostMessage(global) {
|
||||||
|
const { MessageChannel, setTimeout } = global;
|
||||||
|
const channel = new MessageChannel();
|
||||||
|
let head = {};
|
||||||
|
let tail = head;
|
||||||
|
|
||||||
|
let taskRunning = false;
|
||||||
|
channel.port1.onmessage = function() {
|
||||||
|
head = head.next;
|
||||||
|
const task = head.task;
|
||||||
|
delete head.task;
|
||||||
|
|
||||||
|
if (taskRunning) {
|
||||||
|
setTimeout(task, 0);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
taskRunning = true;
|
||||||
|
task();
|
||||||
|
} finally {
|
||||||
|
taskRunning = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return function postMessage(fn) {
|
||||||
|
tail = tail.next = { task: fn };
|
||||||
|
channel.port2.postMessage(0);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStackClearer(global) {
|
||||||
|
const NODE_JS =
|
||||||
|
global.process &&
|
||||||
|
global.process.versions &&
|
||||||
|
typeof global.process.versions.node === 'string';
|
||||||
|
|
||||||
|
// Windows builds of WebKit have a fairly generic user agent string when no application name is provided:
|
||||||
|
// e.g. "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko)"
|
||||||
|
const SAFARI_OR_WIN_WEBKIT =
|
||||||
|
global.navigator &&
|
||||||
|
/(^((?!chrome|android).)*safari)|(Win64; x64\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\)$)/i.test(
|
||||||
|
global.navigator.userAgent
|
||||||
|
);
|
||||||
|
|
||||||
|
if (NODE_JS) {
|
||||||
|
// Unlike browsers, Node doesn't require us to do a periodic setTimeout
|
||||||
|
// so we avoid the overhead.
|
||||||
|
return nodeQueueMicrotaskImpl(global);
|
||||||
|
} else if (SAFARI_OR_WIN_WEBKIT) {
|
||||||
|
// queueMicrotask is dramatically faster than MessageChannel in Safari
|
||||||
|
// and other WebKit-based browsers, such as the one distributed by Playwright
|
||||||
|
// to test Safari-like behavior on Windows.
|
||||||
|
return browserQueueMicrotaskImpl(global);
|
||||||
|
} else {
|
||||||
|
// MessageChannel is faster than queueMicrotask in supported browsers
|
||||||
|
// other than Safari.
|
||||||
|
return messageChannelImpl(global);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getStackClearer;
|
||||||
|
};
|
||||||
|
|
||||||
getJasmineRequireObj().StackTrace = function(j$) {
|
getJasmineRequireObj().StackTrace = function(j$) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@@ -10851,8 +11017,11 @@ getJasmineRequireObj().Suite = function(j$) {
|
|||||||
// Key and value will eventually be cloned during reporting. The error
|
// Key and value will eventually be cloned during reporting. The error
|
||||||
// thrown at that point if they aren't cloneable isn't very helpful.
|
// thrown at that point if they aren't cloneable isn't very helpful.
|
||||||
// Throw a better one now.
|
// Throw a better one now.
|
||||||
j$.private.util.assertReporterCloneable(key, 'Key');
|
if (!j$.private.isString(key)) {
|
||||||
|
throw new Error('Key must be a string');
|
||||||
|
}
|
||||||
j$.private.util.assertReporterCloneable(value, 'Value');
|
j$.private.util.assertReporterCloneable(value, 'Value');
|
||||||
|
|
||||||
this.#result.properties = this.#result.properties || {};
|
this.#result.properties = this.#result.properties || {};
|
||||||
this.#result.properties[key] = value;
|
this.#result.properties[key] = value;
|
||||||
}
|
}
|
||||||
@@ -10960,12 +11129,11 @@ getJasmineRequireObj().Suite = function(j$) {
|
|||||||
* @property {String} description - The description text passed to the {@link describe} that made this suite.
|
* @property {String} description - The description text passed to the {@link describe} that made this suite.
|
||||||
* @property {String} fullName - The full description including all ancestors of this suite.
|
* @property {String} fullName - The full description including all ancestors of this suite.
|
||||||
* @property {String|null} parentSuiteId - The ID of the suite containing this suite, or null if this is not in another describe().
|
* @property {String|null} parentSuiteId - The ID of the suite containing this suite, or null if this is not in another describe().
|
||||||
* @property {String} filename - Deprecated. The name of the file the suite was defined in.
|
* @property {String} filename - The name of the file the suite was defined in.
|
||||||
* Note: The value may be incorrect if zone.js is installed or
|
* Note: The value may be incorrect if zone.js is installed or
|
||||||
* `describe`/`fdescribe`/`xdescribe` have been replaced with versions that
|
* `describe`/`fdescribe`/`xdescribe` have been replaced with versions that
|
||||||
* don't maintain the same call stack height as the originals. This property
|
* don't maintain the same call stack height as the originals. You can fix
|
||||||
* may be removed in a future version unless there is enough user interest
|
* that by setting {@link Configuration#extraDescribeStackFrames}.
|
||||||
* in keeping it. See {@link https://github.com/jasmine/jasmine/issues/2065}.
|
|
||||||
* @property {ExpectationResult[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite.
|
* @property {ExpectationResult[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite.
|
||||||
* @property {ExpectationResult[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite.
|
* @property {ExpectationResult[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite.
|
||||||
* @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite.
|
* @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite.
|
||||||
@@ -11173,6 +11341,19 @@ getJasmineRequireObj().Suite = function(j$) {
|
|||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
this.description = suite.description;
|
this.description = suite.description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the file the suite was defined in.
|
||||||
|
* Note: The value may be incorrect if zone.js is installed or
|
||||||
|
* `describe`/`fdescribe`/`xdescribe` have been replaced with versions
|
||||||
|
* that don't maintain the same call stack height as the originals. You
|
||||||
|
* can fix that by setting {@link Configuration#extraItStackFrames}.
|
||||||
|
* @name Suite#filename
|
||||||
|
* @readonly
|
||||||
|
* @type {string}
|
||||||
|
* @since 5.13.0
|
||||||
|
*/
|
||||||
|
this.filename = suite.filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -11852,7 +12033,10 @@ getJasmineRequireObj().TreeRunner = function(j$) {
|
|||||||
_executeSpec(spec, specOverallDone) {
|
_executeSpec(spec, specOverallDone) {
|
||||||
const onStart = next => {
|
const onStart = next => {
|
||||||
this.#currentRunableTracker.setCurrentSpec(spec);
|
this.#currentRunableTracker.setCurrentSpec(spec);
|
||||||
this.#runableResources.initForRunable(spec.id, spec.parentSuiteId);
|
this.#runableResources.initForRunable(
|
||||||
|
spec.id,
|
||||||
|
spec.parentSuiteId || this.#executionTree.topSuite.id
|
||||||
|
);
|
||||||
this.#reportDispatcher.specStarted(spec.startedEvent()).then(next);
|
this.#reportDispatcher.specStarted(spec.startedEvent()).then(next);
|
||||||
};
|
};
|
||||||
const resultCallback = (result, next) => {
|
const resultCallback = (result, next) => {
|
||||||
@@ -12111,5 +12295,5 @@ getJasmineRequireObj().UserContext = function(j$) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
getJasmineRequireObj().version = function() {
|
getJasmineRequireObj().version = function() {
|
||||||
return '6.0.0-alpha.1';
|
return '6.0.0-alpha.2';
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "jasmine-core",
|
"name": "jasmine-core",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"version": "6.0.0-alpha.1",
|
"version": "6.0.0-alpha.2",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/jasmine/jasmine.git"
|
"url": "https://github.com/jasmine/jasmine.git"
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
Jasmine Core 5.12.1 Release Notes
|
||||||
|
|
||||||
|
## Bug fixes
|
||||||
|
|
||||||
|
* Fix custom matchers in top-level specs
|
||||||
|
* Merges [#2088](https://github.com/jasmine/jasmine/pull/2088) from @bonkevin
|
||||||
|
|
||||||
|
## Supported environments
|
||||||
|
|
||||||
|
This version has been tested in the following environments.
|
||||||
|
|
||||||
|
| Environment | Supported versions |
|
||||||
|
|-------------|--------------------------------|
|
||||||
|
| Node | 18.20.5**, 20, 22, 24 |
|
||||||
|
| Safari | 16**, 17** |
|
||||||
|
| Chrome | 141* |
|
||||||
|
| Firefox | 102**, 115**, 128**, 140, 144* |
|
||||||
|
| Edge | 141* |
|
||||||
|
|
||||||
|
\* Evergreen browser. Each version of Jasmine is tested against the latest
|
||||||
|
version available at release time.<br>
|
||||||
|
\** Supported on a best-effort basis. Support for these versions may be dropped
|
||||||
|
if it becomes impractical, and bugs affecting only these versions may not be
|
||||||
|
treated as release blockers.
|
||||||
|
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
# Jasmine Core 6.0.0-alpha.2 Release Notes
|
||||||
|
|
||||||
|
This is a pre-release, intended to offer a preview of upcoming changes and to
|
||||||
|
solicit feedback.
|
||||||
|
|
||||||
|
## A Note About Pre-Release Compatibility
|
||||||
|
|
||||||
|
There may be additional breaking changes in future 6.0 pre-releases or in the
|
||||||
|
final 6.0 release. That's allowed by the semver specification, but users are
|
||||||
|
sometimes unpleasantly surprised by it.
|
||||||
|
|
||||||
|
NPM's implementation of carat version ranges assumes that subsequent
|
||||||
|
pre-releases and final releases are fully compatible with earlier pre-releases.
|
||||||
|
If your package.json contains `"jasmine-core": "^6.0.0-alpha.2`,
|
||||||
|
NPM might install any later 6.x version even though there is no guarantee of
|
||||||
|
compatibility. If that isn't ok, you should specify an exact pre-release version:
|
||||||
|
`"jasmine-core": "6.0.0-alpha.2`.
|
||||||
|
|
||||||
|
|
||||||
|
## Changes to supported environments
|
||||||
|
|
||||||
|
Safari 26 is now supported on a best-effort basis.†
|
||||||
|
|
||||||
|
Due to the limited availability of Safari 18 and later on free CI services,
|
||||||
|
Safari support in future jasmine-core versions will be limited to:
|
||||||
|
|
||||||
|
* Best-effort support for the latest Safari version available on GitHub Actions,
|
||||||
|
which may change at any time.
|
||||||
|
* Best-effort support for Safari 16 and 17 for as long as it remains practical.
|
||||||
|
|
||||||
|
## Bug Fixes
|
||||||
|
|
||||||
|
* Fix custom matchers in top-level specs††
|
||||||
|
* Merges [#2088](https://github.com/jasmine/jasmine/pull/2088) from @bonkevin
|
||||||
|
|
||||||
|
## New features
|
||||||
|
|
||||||
|
* Larger body font size in HTML reporters
|
||||||
|
* New Performance tab in HtmlReporterV2 shows metrics and a list of the slowest
|
||||||
|
specs.
|
||||||
|
* Experimental `safariYieldStrategy: "time"` config option, which may make
|
||||||
|
Jasmine run significantly faster in Safari and similar browsers. So far, this
|
||||||
|
option has not been tested on a wide variety of workloads. Feedback is
|
||||||
|
appreciated.
|
||||||
|
* New `extraItStackFrames` and `extraDescribeStackFrames` config options to fix
|
||||||
|
the filename properties of reporter events in configurations that wrap
|
||||||
|
`it`/`describe`, such as zone.js.†
|
||||||
|
* `jasmine.allOf asymmetric` equality tester†
|
||||||
|
* Merges [#2087](https://github.com/jasmine/jasmine/pull/2087) from @jonahd-g
|
||||||
|
* Fixes [#2083](https://github.com/jasmine/jasmine/issues/2083)
|
||||||
|
* Re-add support for partial spec name filtering via `spec` query parameter
|
||||||
|
* Fixes [#2085](https://github.com/jasmine/jasmine/issues/2085).
|
||||||
|
* Require spec/suite property keys to be strings, not just anything that's
|
||||||
|
cloneable and serializable. This matches the existing API reference
|
||||||
|
documentation.
|
||||||
|
|
||||||
|
## Documentation improvements
|
||||||
|
|
||||||
|
* Fix HtmlReporterV2 ctor example
|
||||||
|
|
||||||
|
## Internal Improvements
|
||||||
|
|
||||||
|
* Remove code to support browsers that don't have MessageChannel. Jasmine hasn't
|
||||||
|
run in any such browsers since 2.x.
|
||||||
|
|
||||||
|
† Also likely to be included in a future 5.x release.<br>
|
||||||
|
†† Also released in 5.12.1.
|
||||||
|
|
||||||
|
## Supported environments
|
||||||
|
|
||||||
|
This version has been tested in the following environments.
|
||||||
|
|
||||||
|
| Environment | Supported versions |
|
||||||
|
|-------------------|--------------------------------|
|
||||||
|
| Node | 20, 22, 24 |
|
||||||
|
| Safari | 16**, 17**, 26** |
|
||||||
|
| Chrome | 142* |
|
||||||
|
| Firefox | 102**, 115**, 128**, 140, 145* |
|
||||||
|
| Edge | 142* |
|
||||||
|
|
||||||
|
\* Evergreen browser. Each version of Jasmine is tested against the latest
|
||||||
|
version available at release time.<br>
|
||||||
|
\** Supported on a best-effort basis. Support for these versions may be dropped
|
||||||
|
if it becomes impractical, and bugs affecting only these versions may not be
|
||||||
|
treated as release blockers.
|
||||||
|
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||||
@@ -1,5 +1,10 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Run tests in supported browsers that are available on Saucelabs.
|
||||||
|
# Note: The latest Safari version is tested via GitHub Actions because Saucelabs
|
||||||
|
# only makes it available to paid enterprise accounts. See
|
||||||
|
# .github/workflows/safari.yml.
|
||||||
|
|
||||||
run_browser() {
|
run_browser() {
|
||||||
browser=$1
|
browser=$1
|
||||||
version=$2
|
version=$2
|
||||||
@@ -10,7 +10,14 @@ describe('Configuration', function() {
|
|||||||
'detectLateRejectionHandling',
|
'detectLateRejectionHandling',
|
||||||
'verboseDeprecations'
|
'verboseDeprecations'
|
||||||
];
|
];
|
||||||
const allKeys = [...standardBooleanKeys, 'seed', 'specFilter'];
|
const allKeys = [
|
||||||
|
...standardBooleanKeys,
|
||||||
|
'seed',
|
||||||
|
'specFilter',
|
||||||
|
'extraItStackFrames',
|
||||||
|
'extraDescribeStackFrames',
|
||||||
|
'safariYieldStrategy'
|
||||||
|
];
|
||||||
Object.freeze(standardBooleanKeys);
|
Object.freeze(standardBooleanKeys);
|
||||||
Object.freeze(allKeys);
|
Object.freeze(allKeys);
|
||||||
|
|
||||||
@@ -28,6 +35,9 @@ describe('Configuration', function() {
|
|||||||
expect(subject.forbidDuplicateNames).toEqual(true);
|
expect(subject.forbidDuplicateNames).toEqual(true);
|
||||||
expect(subject.verboseDeprecations).toEqual(false);
|
expect(subject.verboseDeprecations).toEqual(false);
|
||||||
expect(subject.detectLateRejectionHandling).toEqual(false);
|
expect(subject.detectLateRejectionHandling).toEqual(false);
|
||||||
|
expect(subject.extraItStackFrames).toEqual(0);
|
||||||
|
expect(subject.extraDescribeStackFrames).toEqual(0);
|
||||||
|
expect(subject.safariYieldStrategy).toEqual('count');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('copy()', function() {
|
describe('copy()', function() {
|
||||||
@@ -109,5 +119,48 @@ describe('Configuration', function() {
|
|||||||
subject.update({ seed: null });
|
subject.update({ seed: null });
|
||||||
expect(subject.seed).toBeNull();
|
expect(subject.seed).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('sets extraItStackFrames when not undefined', function() {
|
||||||
|
const subject = new privateUnderTest.Configuration();
|
||||||
|
|
||||||
|
subject.update({ extraItStackFrames: undefined });
|
||||||
|
expect(subject.extraItStackFrames).toEqual(0);
|
||||||
|
|
||||||
|
subject.update({ extraItStackFrames: 100000 });
|
||||||
|
expect(subject.extraItStackFrames).toEqual(100000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets extraDescribeStackFrames when not undefined', function() {
|
||||||
|
const subject = new privateUnderTest.Configuration();
|
||||||
|
|
||||||
|
subject.update({ extraDescribeStackFrames: undefined });
|
||||||
|
expect(subject.extraDescribeStackFrames).toEqual(0);
|
||||||
|
|
||||||
|
subject.update({ extraDescribeStackFrames: 100000 });
|
||||||
|
expect(subject.extraDescribeStackFrames).toEqual(100000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets safariYieldStrategy when valid', function() {
|
||||||
|
const subject = new privateUnderTest.Configuration();
|
||||||
|
|
||||||
|
subject.update({ safariYieldStrategy: undefined });
|
||||||
|
expect(subject.safariYieldStrategy).toEqual('count');
|
||||||
|
|
||||||
|
subject.update({ safariYieldStrategy: 'time' });
|
||||||
|
expect(subject.safariYieldStrategy).toEqual('time');
|
||||||
|
|
||||||
|
subject.update({ safariYieldStrategy: 'count' });
|
||||||
|
expect(subject.safariYieldStrategy).toEqual('count');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejcts invalid safariYieldStrategy values', function() {
|
||||||
|
const subject = new privateUnderTest.Configuration();
|
||||||
|
|
||||||
|
expect(function() {
|
||||||
|
subject.update({ safariYieldStrategy: 'thyme' });
|
||||||
|
}).toThrowError(
|
||||||
|
"Invalid safariYieldStrategy value. Valid values are 'count' and 'time'."
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+43
-2
@@ -1,4 +1,3 @@
|
|||||||
// TODO: Fix these unit tests!
|
|
||||||
describe('Env', function() {
|
describe('Env', function() {
|
||||||
let env;
|
let env;
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
@@ -95,7 +94,7 @@ describe('Env', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('accepts its own current configureation', function() {
|
it('accepts its own current configuration', function() {
|
||||||
env.configure(env.configuration());
|
env.configure(env.configuration());
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -198,6 +197,29 @@ describe('Env', function() {
|
|||||||
expect(innerSuite.parentSuite).toBe(suite);
|
expect(innerSuite.parentSuite).toBe(suite);
|
||||||
expect(spec.getFullName()).toEqual('outer suite inner suite a spec');
|
expect(spec.getFullName()).toEqual('outer suite inner suite a spec');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('sets the caller filename correctly when extraDescribeStackFrames is not set', function() {
|
||||||
|
// IIFE is used to match the stack depth when global describe() is called
|
||||||
|
const suite = (function() {
|
||||||
|
return env[methodName]('a suite', function() {
|
||||||
|
env.it('a spec');
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
expect(suite.filename).toMatch(/EnvSpec\.js$/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets the caller filename correctly when extraDescribeStackFrames is set', function() {
|
||||||
|
env.configure({ extraDescribeStackFrames: 2 });
|
||||||
|
// IIFE is used to match the stack depth when global describe() is called
|
||||||
|
const suite = (function() {
|
||||||
|
return specHelpers.callerFilenameShim(function() {
|
||||||
|
return env[methodName]('a suite', function() {
|
||||||
|
env.it('a spec');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
expect(suite.filename).toMatch(/EnvSpec\.js$/);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('#describe', function() {
|
describe('#describe', function() {
|
||||||
@@ -300,6 +322,25 @@ describe('Env', function() {
|
|||||||
.not.toEqual('');
|
.not.toEqual('');
|
||||||
expect(spec.pend).toBeFalsy();
|
expect(spec.pend).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('sets the caller filename correctly when extraItStackFrames is not set', function() {
|
||||||
|
// IIFE is used to match the stack depth when global it() is called
|
||||||
|
const spec = (function() {
|
||||||
|
return env[methodName]('a spec', function() {});
|
||||||
|
})();
|
||||||
|
expect(spec.filename).toMatch(/EnvSpec\.js$/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets the caller filename correctly when extraItStackFrames is set', function() {
|
||||||
|
env.configure({ extraItStackFrames: 2 });
|
||||||
|
// IIFE is used to match the stack depth when global it() is called
|
||||||
|
const spec = (function() {
|
||||||
|
return specHelpers.callerFilenameShim(function() {
|
||||||
|
return env[methodName]('a spec', function() {});
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
expect(spec.filename).toMatch(/EnvSpec\.js$/);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('#it', function() {
|
describe('#it', function() {
|
||||||
|
|||||||
@@ -486,7 +486,7 @@ describe('QueueRunner', function() {
|
|||||||
errorListeners.pop();
|
errorListeners.pop();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
clearStack = jasmine.createSpy('clearStack'),
|
clearStack = jasmine.createSpyObj('clearStack', ['clearStack']),
|
||||||
onException = jasmine.createSpy('onException'),
|
onException = jasmine.createSpy('onException'),
|
||||||
queueRunner = new privateUnderTest.QueueRunner({
|
queueRunner = new privateUnderTest.QueueRunner({
|
||||||
queueableFns: [queueableFn],
|
queueableFns: [queueableFn],
|
||||||
@@ -498,10 +498,10 @@ describe('QueueRunner', function() {
|
|||||||
|
|
||||||
queueRunner.execute();
|
queueRunner.execute();
|
||||||
jasmine.clock().tick();
|
jasmine.clock().tick();
|
||||||
expect(clearStack).toHaveBeenCalled();
|
expect(clearStack.clearStack).toHaveBeenCalled();
|
||||||
expect(errorListeners.length).toEqual(1);
|
expect(errorListeners.length).toEqual(1);
|
||||||
errorListeners[0](error);
|
errorListeners[0](error);
|
||||||
clearStack.calls.argsFor(0)[0]();
|
clearStack.clearStack.calls.argsFor(0)[0]();
|
||||||
expect(onException).toHaveBeenCalledWith(error);
|
expect(onException).toHaveBeenCalledWith(error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -908,22 +908,22 @@ describe('QueueRunner', function() {
|
|||||||
},
|
},
|
||||||
afterFn = { fn: jasmine.createSpy('afterFn') },
|
afterFn = { fn: jasmine.createSpy('afterFn') },
|
||||||
completeCallback = jasmine.createSpy('completeCallback'),
|
completeCallback = jasmine.createSpy('completeCallback'),
|
||||||
clearStack = jasmine.createSpy('clearStack'),
|
clearStack = jasmine.createSpyObj('clearStack', ['clearStack']),
|
||||||
queueRunner = new privateUnderTest.QueueRunner({
|
queueRunner = new privateUnderTest.QueueRunner({
|
||||||
queueableFns: [asyncFn, afterFn],
|
queueableFns: [asyncFn, afterFn],
|
||||||
clearStack: clearStack,
|
clearStack: clearStack,
|
||||||
onComplete: completeCallback
|
onComplete: completeCallback
|
||||||
});
|
});
|
||||||
|
|
||||||
clearStack.and.callFake(function(fn) {
|
clearStack.clearStack.and.callFake(function(fn) {
|
||||||
fn();
|
fn();
|
||||||
});
|
});
|
||||||
|
|
||||||
queueRunner.execute();
|
queueRunner.execute();
|
||||||
jasmine.clock().tick();
|
jasmine.clock().tick();
|
||||||
expect(afterFn.fn).toHaveBeenCalled();
|
expect(afterFn.fn).toHaveBeenCalled();
|
||||||
expect(clearStack).toHaveBeenCalled();
|
expect(clearStack.clearStack).toHaveBeenCalled();
|
||||||
clearStack.calls.argsFor(0)[0]();
|
clearStack.clearStack.calls.argsFor(0)[0]();
|
||||||
expect(completeCallback).toHaveBeenCalled();
|
expect(completeCallback).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+3
-15
@@ -103,26 +103,14 @@ describe('Spec', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throws if the key is not structured-cloneable', function() {
|
it('throws if the key is not a string', function() {
|
||||||
const spec = new privateUnderTest.Spec({
|
const spec = new privateUnderTest.Spec({
|
||||||
queueableFn: { fn: () => {} }
|
queueableFn: { fn: () => {} }
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
spec.setSpecProperty(new Promise(() => {}), '');
|
spec.setSpecProperty({}, '');
|
||||||
}).toThrowError("Key can't be cloned");
|
}).toThrowError('Key must be a string');
|
||||||
});
|
|
||||||
|
|
||||||
it('throws if the key is not JSON-serializable', function() {
|
|
||||||
const spec = new privateUnderTest.Spec({
|
|
||||||
queueableFn: { fn: () => {} }
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(function() {
|
|
||||||
const k = {};
|
|
||||||
k.self = k;
|
|
||||||
spec.setSpecProperty(k, '');
|
|
||||||
}).toThrowError("Key can't be cloned");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throws if the value is not structured-cloneable', function() {
|
it('throws if the value is not structured-cloneable', function() {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
describe('ClearStack', function() {
|
describe('StackClearer', function() {
|
||||||
it('works in an integrationy way', function(done) {
|
it('works in an integrationy way', function(done) {
|
||||||
const clearStack = privateUnderTest.getClearStack(
|
const { clearStack } = privateUnderTest.getStackClearer(
|
||||||
jasmineUnderTest.getGlobal()
|
jasmineUnderTest.getGlobal()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ describe('ClearStack', function() {
|
|||||||
queueMicrotask
|
queueMicrotask
|
||||||
};
|
};
|
||||||
|
|
||||||
const clearStack = privateUnderTest.getClearStack(global);
|
const { clearStack } = privateUnderTest.getStackClearer(global);
|
||||||
|
|
||||||
for (let i = 0; i < 9; i++) {
|
for (let i = 0; i < 9; i++) {
|
||||||
clearStack(function() {});
|
clearStack(function() {});
|
||||||
@@ -73,17 +73,6 @@ describe('ClearStack', function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when MessageChannel is unavailable', function() {
|
|
||||||
usesQueueMicrotaskWithSetTimeout(function() {
|
|
||||||
return {
|
|
||||||
navigator: {
|
|
||||||
userAgent: 'CERN-LineMode/2.15 libwww/2.17b3',
|
|
||||||
MessageChannel: undefined
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('in Node', function() {
|
describe('in Node', function() {
|
||||||
@@ -104,7 +93,7 @@ describe('ClearStack', function() {
|
|||||||
...makeGlobal(),
|
...makeGlobal(),
|
||||||
MessageChannel: fakeMessageChannel
|
MessageChannel: fakeMessageChannel
|
||||||
};
|
};
|
||||||
const clearStack = privateUnderTest.getClearStack(global);
|
const { clearStack } = privateUnderTest.getStackClearer(global);
|
||||||
let called = false;
|
let called = false;
|
||||||
|
|
||||||
clearStack(function() {
|
clearStack(function() {
|
||||||
@@ -125,7 +114,7 @@ describe('ClearStack', function() {
|
|||||||
return fakeChannel;
|
return fakeChannel;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const clearStack = privateUnderTest.getClearStack(global);
|
const { clearStack } = privateUnderTest.getStackClearer(global);
|
||||||
|
|
||||||
for (let i = 0; i < 9; i++) {
|
for (let i = 0; i < 9; i++) {
|
||||||
clearStack(function() {});
|
clearStack(function() {});
|
||||||
@@ -150,7 +139,7 @@ describe('ClearStack', function() {
|
|||||||
setTimeout,
|
setTimeout,
|
||||||
MessageChannel: fakeMessageChannel
|
MessageChannel: fakeMessageChannel
|
||||||
};
|
};
|
||||||
const clearStack = privateUnderTest.getClearStack(global);
|
const { clearStack } = privateUnderTest.getStackClearer(global);
|
||||||
const fn = jasmine.createSpy('second clearStack function');
|
const fn = jasmine.createSpy('second clearStack function');
|
||||||
|
|
||||||
clearStack(function() {
|
clearStack(function() {
|
||||||
@@ -170,7 +159,7 @@ describe('ClearStack', function() {
|
|||||||
fn();
|
fn();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const clearStack = privateUnderTest.getClearStack(global);
|
const { clearStack } = privateUnderTest.getStackClearer(global);
|
||||||
let called = false;
|
let called = false;
|
||||||
|
|
||||||
clearStack(function() {
|
clearStack(function() {
|
||||||
@@ -180,30 +169,82 @@ describe('ClearStack', function() {
|
|||||||
expect(called).toBe(true);
|
expect(called).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('uses setTimeout instead of queueMicrotask every 10 calls to make sure we release the CPU', function() {
|
function hasSetTimeoutBehavior(configure) {
|
||||||
const queueMicrotask = jasmine.createSpy('queueMicrotask');
|
it('uses setTimeout instead of queueMicrotask every 10 calls', function() {
|
||||||
const setTimeout = jasmine.createSpy('setTimeout');
|
const queueMicrotask = jasmine.createSpy('queueMicrotask');
|
||||||
const global = {
|
const setTimeout = jasmine.createSpy('setTimeout');
|
||||||
...makeGlobal(),
|
const global = {
|
||||||
queueMicrotask,
|
...makeGlobal(),
|
||||||
setTimeout
|
queueMicrotask,
|
||||||
};
|
setTimeout
|
||||||
const clearStack = privateUnderTest.getClearStack(global);
|
};
|
||||||
|
const stackClearer = privateUnderTest.getStackClearer(global);
|
||||||
|
|
||||||
for (let i = 0; i < 9; i++) {
|
if (configure) {
|
||||||
clearStack(function() {});
|
configure(stackClearer);
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(queueMicrotask).toHaveBeenCalled();
|
for (let i = 0; i < 9; i++) {
|
||||||
expect(setTimeout).not.toHaveBeenCalled();
|
stackClearer.clearStack(function() {});
|
||||||
|
}
|
||||||
|
|
||||||
clearStack(function() {});
|
expect(queueMicrotask).toHaveBeenCalled();
|
||||||
expect(queueMicrotask).toHaveBeenCalledTimes(9);
|
expect(setTimeout).not.toHaveBeenCalled();
|
||||||
expect(setTimeout).toHaveBeenCalledTimes(1);
|
|
||||||
|
|
||||||
clearStack(function() {});
|
stackClearer.clearStack(function() {});
|
||||||
expect(queueMicrotask).toHaveBeenCalledTimes(10);
|
expect(queueMicrotask).toHaveBeenCalledTimes(9);
|
||||||
expect(setTimeout).toHaveBeenCalledTimes(1);
|
expect(setTimeout).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
stackClearer.clearStack(function() {});
|
||||||
|
expect(queueMicrotask).toHaveBeenCalledTimes(10);
|
||||||
|
expect(setTimeout).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
hasSetTimeoutBehavior();
|
||||||
|
|
||||||
|
describe('With yield strategy explicitly set to count', function() {
|
||||||
|
hasSetTimeoutBehavior(function(stackClearer) {
|
||||||
|
stackClearer.setSafariYieldStrategy('count');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('With yield strategy set to time', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
jasmine.clock().install();
|
||||||
|
jasmine.clock().mockDate();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
jasmine.clock().uninstall();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses setTimeout instead of queueMicrotask every 25 milliseconds', function() {
|
||||||
|
const queueMicrotask = jasmine.createSpy('queueMicrotask');
|
||||||
|
const setTimeout = jasmine.createSpy('setTimeout');
|
||||||
|
const global = {
|
||||||
|
...makeGlobal(),
|
||||||
|
queueMicrotask,
|
||||||
|
setTimeout
|
||||||
|
};
|
||||||
|
const stackClearer = privateUnderTest.getStackClearer(global);
|
||||||
|
stackClearer.setSafariYieldStrategy('time');
|
||||||
|
|
||||||
|
// 10+ counts should not trigger a setTimeout if they happen fast enough
|
||||||
|
jasmine.clock().tick(24);
|
||||||
|
for (let i = 0; i < 11; i++) {
|
||||||
|
stackClearer.clearStack(function() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(queueMicrotask).toHaveBeenCalled();
|
||||||
|
expect(setTimeout).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
queueMicrotask.calls.reset();
|
||||||
|
jasmine.clock().tick(1);
|
||||||
|
stackClearer.clearStack(function() {});
|
||||||
|
expect(queueMicrotask).not.toHaveBeenCalled();
|
||||||
|
expect(setTimeout).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,7 +256,7 @@ describe('ClearStack', function() {
|
|||||||
fn();
|
fn();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const clearStack = privateUnderTest.getClearStack(global);
|
const { clearStack } = privateUnderTest.getStackClearer(global);
|
||||||
let called = false;
|
let called = false;
|
||||||
|
|
||||||
clearStack(function() {
|
clearStack(function() {
|
||||||
@@ -233,7 +274,7 @@ describe('ClearStack', function() {
|
|||||||
queueMicrotask,
|
queueMicrotask,
|
||||||
setTimeout
|
setTimeout
|
||||||
};
|
};
|
||||||
const clearStack = privateUnderTest.getClearStack(global);
|
const { clearStack } = privateUnderTest.getStackClearer(global);
|
||||||
|
|
||||||
clearStack(function() {});
|
clearStack(function() {});
|
||||||
clearStack(function() {});
|
clearStack(function() {});
|
||||||
+13
-3
@@ -409,12 +409,12 @@ describe('Suite', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('#setSuiteProperty', function() {
|
describe('#setSuiteProperty', function() {
|
||||||
it('throws if the key is not structured-cloneable', function() {
|
it('throws if the key is not a string', function() {
|
||||||
const suite = new privateUnderTest.Suite({});
|
const suite = new privateUnderTest.Suite({});
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
suite.setSuiteProperty(new Promise(() => {}), '');
|
suite.setSuiteProperty({}, '');
|
||||||
}).toThrowError("Key can't be cloned");
|
}).toThrowError('Key must be a string');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throws if the value is not structured-cloneable', function() {
|
it('throws if the value is not structured-cloneable', function() {
|
||||||
@@ -424,6 +424,16 @@ describe('Suite', function() {
|
|||||||
suite.setSuiteProperty('k', new Promise(() => {}));
|
suite.setSuiteProperty('k', new Promise(() => {}));
|
||||||
}).toThrowError("Value can't be cloned");
|
}).toThrowError("Value can't be cloned");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('throws if the value is not JSON-serializable', function() {
|
||||||
|
const suite = new privateUnderTest.Suite({});
|
||||||
|
|
||||||
|
expect(function() {
|
||||||
|
const v = {};
|
||||||
|
v.self = v;
|
||||||
|
suite.setSuiteProperty('k', v);
|
||||||
|
}).toThrowError("Value can't be cloned");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#startedEvent', function() {
|
describe('#startedEvent', function() {
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
describe('AllOf', function() {
|
||||||
|
it('matches a single value', function() {
|
||||||
|
const matchersUtil = new privateUnderTest.MatchersUtil();
|
||||||
|
const allOf = new privateUnderTest.AllOf('foo');
|
||||||
|
|
||||||
|
expect(allOf.asymmetricMatch('foo', matchersUtil)).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('matches a single matcher', function() {
|
||||||
|
const matchersUtil = new privateUnderTest.MatchersUtil();
|
||||||
|
const allOf = new privateUnderTest.AllOf(
|
||||||
|
new privateUnderTest.StringContaining('oo')
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(allOf.asymmetricMatch('foo', matchersUtil)).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('matches multiple matchers', function() {
|
||||||
|
const matchersUtil = new privateUnderTest.MatchersUtil();
|
||||||
|
const allOf = new privateUnderTest.AllOf(
|
||||||
|
new privateUnderTest.StringContaining('o'),
|
||||||
|
new privateUnderTest.StringContaining('f')
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(allOf.asymmetricMatch('foo', matchersUtil)).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not match when value does not match', function() {
|
||||||
|
const matchersUtil = new privateUnderTest.MatchersUtil();
|
||||||
|
const allOf = new privateUnderTest.AllOf('bar');
|
||||||
|
|
||||||
|
expect(allOf.asymmetricMatch('foo', matchersUtil)).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not match when any matchers fail', function() {
|
||||||
|
const matchersUtil = new privateUnderTest.MatchersUtil();
|
||||||
|
const allOf = new privateUnderTest.AllOf(
|
||||||
|
new privateUnderTest.StringContaining('o'),
|
||||||
|
new privateUnderTest.StringContaining('x')
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(allOf.asymmetricMatch('foo', matchersUtil)).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('jasmineToStrings itself', function() {
|
||||||
|
const matcher = new privateUnderTest.AllOf('o');
|
||||||
|
const pp = jasmine.createSpy('pp').and.returnValue('sample');
|
||||||
|
|
||||||
|
expect(matcher.jasmineToString(pp)).toEqual('<jasmine.allOf(sample)>');
|
||||||
|
expect(pp).toHaveBeenCalledWith(['o']);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when called without an argument', function() {
|
||||||
|
it('tells the user to pass a constructor argument', function() {
|
||||||
|
expect(function() {
|
||||||
|
new privateUnderTest.AllOf();
|
||||||
|
}).toThrowError(
|
||||||
|
TypeError,
|
||||||
|
'jasmine.allOf() expects at least one argument to be passed.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1114,8 +1114,17 @@ describe('Env integration', function() {
|
|||||||
global: {
|
global: {
|
||||||
setTimeout: globalSetTimeout,
|
setTimeout: globalSetTimeout,
|
||||||
clearTimeout: clearTimeout,
|
clearTimeout: clearTimeout,
|
||||||
|
addEventListener() {},
|
||||||
|
removeEventListener() {},
|
||||||
queueMicrotask: function(fn) {
|
queueMicrotask: function(fn) {
|
||||||
queueMicrotask(fn);
|
queueMicrotask(fn);
|
||||||
|
},
|
||||||
|
// Enough Node globals to make getStackClearer() return the microtask
|
||||||
|
// implementation, which is the easiest to mock
|
||||||
|
process: {
|
||||||
|
versions: {
|
||||||
|
node: ''
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1179,7 +1188,7 @@ describe('Env integration', function() {
|
|||||||
global: {
|
global: {
|
||||||
setTimeout: function(cb, t) {
|
setTimeout: function(cb, t) {
|
||||||
const stack = new Error().stack;
|
const stack = new Error().stack;
|
||||||
if (stack.indexOf('ClearStack') >= 0) {
|
if (stack.indexOf('clearStack') >= 0) {
|
||||||
return realSetTimeout(cb, t);
|
return realSetTimeout(cb, t);
|
||||||
} else {
|
} else {
|
||||||
return setTimeout(cb, t);
|
return setTimeout(cb, t);
|
||||||
@@ -1188,8 +1197,17 @@ describe('Env integration', function() {
|
|||||||
clearTimeout: clearTimeout,
|
clearTimeout: clearTimeout,
|
||||||
setInterval: setInterval,
|
setInterval: setInterval,
|
||||||
clearInterval: clearInterval,
|
clearInterval: clearInterval,
|
||||||
|
addEventListener() {},
|
||||||
|
removeEventListener() {},
|
||||||
queueMicrotask: function(fn) {
|
queueMicrotask: function(fn) {
|
||||||
queueMicrotask(fn);
|
queueMicrotask(fn);
|
||||||
|
},
|
||||||
|
// Enough Node globals to make getStackClearer() return the microtask
|
||||||
|
// implementation, which is the easiest to mock
|
||||||
|
process: {
|
||||||
|
versions: {
|
||||||
|
node: ''
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -2274,6 +2292,34 @@ describe('Env integration', function() {
|
|||||||
await env.execute();
|
await env.execute();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Custom matchers set in top-level beforeAll should be available to all specs and suites', async function() {
|
||||||
|
const matchers = {
|
||||||
|
toFoo: function() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
env.beforeAll(function() {
|
||||||
|
env.addMatchers(matchers);
|
||||||
|
});
|
||||||
|
|
||||||
|
env.describe('suite - top-level', function() {
|
||||||
|
env.it('has access to the custom matcher', function() {
|
||||||
|
expect(env.expect().toFoo).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
env.describe('suite - nested', function() {
|
||||||
|
env.it('has access to the custom matcher', function() {
|
||||||
|
expect(env.expect().toFoo).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
env.it('spec - top-level - has access to the custom matcher', function() {
|
||||||
|
expect(env.expect().toFoo).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
await env.execute();
|
||||||
|
});
|
||||||
|
|
||||||
it('throws an exception if you try to create a spy outside of a runnable', async function() {
|
it('throws an exception if you try to create a spy outside of a runnable', async function() {
|
||||||
const obj = { fn: function() {} };
|
const obj = { fn: function() {} };
|
||||||
let exception;
|
let exception;
|
||||||
@@ -2775,12 +2821,18 @@ describe('Env integration', function() {
|
|||||||
},
|
},
|
||||||
queueMicrotask: function(fn) {
|
queueMicrotask: function(fn) {
|
||||||
queueMicrotask(fn);
|
queueMicrotask(fn);
|
||||||
|
},
|
||||||
|
// Enough Node globals to make getStackClearer() return the microtask
|
||||||
|
// implementation, which is the easiest to mock
|
||||||
|
process: {
|
||||||
|
versions: {
|
||||||
|
node: ''
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
|
||||||
|
|
||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
env = new privateUnderTest.Env();
|
env = new privateUnderTest.Env({ global });
|
||||||
const reporter = jasmine.createSpyObj('reporter', [
|
const reporter = jasmine.createSpyObj('reporter', [
|
||||||
'jasmineDone',
|
'jasmineDone',
|
||||||
'suiteDone',
|
'suiteDone',
|
||||||
@@ -3228,13 +3280,11 @@ describe('Env integration', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('is resolved after the stack is cleared', function(done) {
|
it('is resolved after the stack is cleared', function(done) {
|
||||||
const realClearStack = privateUnderTest.getClearStack(
|
const stackClearer = privateUnderTest.getStackClearer(
|
||||||
jasmineUnderTest.getGlobal()
|
jasmineUnderTest.getGlobal()
|
||||||
),
|
);
|
||||||
clearStackSpy = jasmine
|
spyOn(stackClearer, 'clearStack').and.callThrough();
|
||||||
.createSpy('clearStack')
|
spyOn(privateUnderTest, 'getStackClearer').and.returnValue(stackClearer);
|
||||||
.and.callFake(realClearStack);
|
|
||||||
spyOn(privateUnderTest, 'getClearStack').and.returnValue(clearStackSpy);
|
|
||||||
|
|
||||||
// Create a new env that has the clearStack defined above
|
// Create a new env that has the clearStack defined above
|
||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
@@ -3245,10 +3295,10 @@ describe('Env integration', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
env.execute(null).then(function() {
|
env.execute(null).then(function() {
|
||||||
expect(clearStackSpy).toHaveBeenCalled(); // (many times)
|
expect(stackClearer.clearStack).toHaveBeenCalled(); // (many times)
|
||||||
clearStackSpy.calls.reset();
|
stackClearer.clearStack.calls.reset();
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
expect(clearStackSpy).not.toHaveBeenCalled();
|
expect(stackClearer.clearStack).not.toHaveBeenCalled();
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -3337,13 +3387,11 @@ describe('Env integration', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('is called after the stack is cleared', async function() {
|
it('is called after the stack is cleared', async function() {
|
||||||
const realClearStack = privateUnderTest.getClearStack(
|
const stackClearer = privateUnderTest.getStackClearer(
|
||||||
jasmineUnderTest.getGlobal()
|
jasmineUnderTest.getGlobal()
|
||||||
),
|
);
|
||||||
clearStackSpy = jasmine
|
spyOn(stackClearer, 'clearStack').and.callThrough();
|
||||||
.createSpy('clearStack')
|
spyOn(privateUnderTest, 'getStackClearer').and.returnValue(stackClearer);
|
||||||
.and.callFake(realClearStack);
|
|
||||||
spyOn(privateUnderTest, 'getClearStack').and.returnValue(clearStackSpy);
|
|
||||||
|
|
||||||
// Create a new env that has the clearStack defined above
|
// Create a new env that has the clearStack defined above
|
||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
@@ -3355,12 +3403,12 @@ describe('Env integration', function() {
|
|||||||
|
|
||||||
await env.execute();
|
await env.execute();
|
||||||
|
|
||||||
expect(clearStackSpy).toHaveBeenCalled(); // (many times)
|
expect(stackClearer.clearStack).toHaveBeenCalled(); // (many times)
|
||||||
clearStackSpy.calls.reset();
|
stackClearer.clearStack.calls.reset();
|
||||||
|
|
||||||
await new Promise(resolve => setTimeout(resolve));
|
await new Promise(resolve => setTimeout(resolve));
|
||||||
|
|
||||||
expect(clearStackSpy).not.toHaveBeenCalled();
|
expect(stackClearer.clearStack).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('is called after QueueRunner timeouts are cleared', async function() {
|
it('is called after QueueRunner timeouts are cleared', async function() {
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ describe('Global error handling (integration)', function() {
|
|||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('reports errors that occur during loading', async function() {
|
function mockGlobal() {
|
||||||
const global = {
|
return {
|
||||||
...browserEventMethods(),
|
...browserEventMethods(),
|
||||||
setTimeout: function(fn, delay) {
|
setTimeout: function(fn, delay) {
|
||||||
return setTimeout(fn, delay);
|
return setTimeout(fn, delay);
|
||||||
@@ -23,12 +23,21 @@ describe('Global error handling (integration)', function() {
|
|||||||
queueMicrotask: function(fn) {
|
queueMicrotask: function(fn) {
|
||||||
queueMicrotask(fn);
|
queueMicrotask(fn);
|
||||||
},
|
},
|
||||||
onerror: function() {}
|
onerror: function() {},
|
||||||
|
// Enough Node globals to make getStackClearer() return the microtask
|
||||||
|
// implementation, which is the easiest to mock
|
||||||
|
process: {
|
||||||
|
versions: {
|
||||||
|
node: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
}
|
||||||
|
|
||||||
|
it('reports errors that occur during loading', async function() {
|
||||||
|
const global = mockGlobal();
|
||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
env = new privateUnderTest.Env();
|
env = new privateUnderTest.Env({ global });
|
||||||
const reporter = jasmine.createSpyObj('reporter', [
|
const reporter = jasmine.createSpyObj('reporter', [
|
||||||
'jasmineDone',
|
'jasmineDone',
|
||||||
'suiteDone',
|
'suiteDone',
|
||||||
@@ -70,21 +79,9 @@ describe('Global error handling (integration)', function() {
|
|||||||
|
|
||||||
describe('If suppressLoadErrors: true was passed', function() {
|
describe('If suppressLoadErrors: true was passed', function() {
|
||||||
it('does not install a global error handler during loading', async function() {
|
it('does not install a global error handler during loading', async function() {
|
||||||
|
const global = mockGlobal();
|
||||||
const originalOnerror = jasmine.createSpy('original onerror');
|
const originalOnerror = jasmine.createSpy('original onerror');
|
||||||
const global = {
|
global.onerror = originalOnerror;
|
||||||
...browserEventMethods(),
|
|
||||||
setTimeout: function(fn, delay) {
|
|
||||||
return setTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
clearTimeout: function(fn, delay) {
|
|
||||||
clearTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
queueMicrotask: function(fn) {
|
|
||||||
queueMicrotask(fn);
|
|
||||||
},
|
|
||||||
onerror: originalOnerror
|
|
||||||
};
|
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
|
||||||
const globalErrors = new privateUnderTest.GlobalErrors(global);
|
const globalErrors = new privateUnderTest.GlobalErrors(global);
|
||||||
const onerror = jasmine.createSpy('onerror');
|
const onerror = jasmine.createSpy('onerror');
|
||||||
globalErrors.pushListener(onerror);
|
globalErrors.pushListener(onerror);
|
||||||
@@ -92,6 +89,7 @@ describe('Global error handling (integration)', function() {
|
|||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
env = new privateUnderTest.Env({
|
env = new privateUnderTest.Env({
|
||||||
suppressLoadErrors: true,
|
suppressLoadErrors: true,
|
||||||
|
global,
|
||||||
GlobalErrors: function() {
|
GlobalErrors: function() {
|
||||||
return globalErrors;
|
return globalErrors;
|
||||||
}
|
}
|
||||||
@@ -115,21 +113,9 @@ describe('Global error handling (integration)', function() {
|
|||||||
|
|
||||||
describe('Handling unhandled exceptions', function() {
|
describe('Handling unhandled exceptions', function() {
|
||||||
it('routes unhandled exceptions to the running spec', async function() {
|
it('routes unhandled exceptions to the running spec', async function() {
|
||||||
const global = {
|
const global = mockGlobal();
|
||||||
...browserEventMethods(),
|
|
||||||
setTimeout: function(fn, delay) {
|
|
||||||
return setTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
clearTimeout: function(fn, delay) {
|
|
||||||
clearTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
queueMicrotask: function(fn) {
|
|
||||||
queueMicrotask(fn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
|
||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
env = new privateUnderTest.Env();
|
env = new privateUnderTest.Env({ global });
|
||||||
const reporter = jasmine.createSpyObj('fakeReporter', [
|
const reporter = jasmine.createSpyObj('fakeReporter', [
|
||||||
'specDone',
|
'specDone',
|
||||||
'suiteDone'
|
'suiteDone'
|
||||||
@@ -156,24 +142,12 @@ describe('Global error handling (integration)', function() {
|
|||||||
|
|
||||||
describe('When the most recently running spec has reported specDone', function() {
|
describe('When the most recently running spec has reported specDone', function() {
|
||||||
it('routes unhandled exceptions to an ancestor suite', async function() {
|
it('routes unhandled exceptions to an ancestor suite', async function() {
|
||||||
const global = {
|
const global = mockGlobal();
|
||||||
...browserEventMethods(),
|
const stackClearer = privateUnderTest.getStackClearer(global);
|
||||||
setTimeout: function(fn, delay) {
|
const realClearStack = stackClearer.clearStack;
|
||||||
return setTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
clearTimeout: function(fn) {
|
|
||||||
clearTimeout(fn);
|
|
||||||
},
|
|
||||||
queueMicrotask: function(fn) {
|
|
||||||
queueMicrotask(fn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
|
||||||
|
|
||||||
const realClearStack = privateUnderTest.getClearStack(global);
|
|
||||||
const clearStackCallbacks = {};
|
const clearStackCallbacks = {};
|
||||||
let clearStackCallCount = 0;
|
let clearStackCallCount = 0;
|
||||||
spyOn(privateUnderTest, 'getClearStack').and.returnValue(function(fn) {
|
spyOn(stackClearer, 'clearStack').and.callFake(function(fn) {
|
||||||
clearStackCallCount++;
|
clearStackCallCount++;
|
||||||
|
|
||||||
if (clearStackCallbacks[clearStackCallCount]) {
|
if (clearStackCallbacks[clearStackCallCount]) {
|
||||||
@@ -182,9 +156,12 @@ describe('Global error handling (integration)', function() {
|
|||||||
|
|
||||||
realClearStack(fn);
|
realClearStack(fn);
|
||||||
});
|
});
|
||||||
|
spyOn(privateUnderTest, 'getStackClearer').and.returnValue(
|
||||||
|
stackClearer
|
||||||
|
);
|
||||||
|
|
||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
env = new privateUnderTest.Env();
|
env = new privateUnderTest.Env({ global });
|
||||||
|
|
||||||
let suiteErrors = [];
|
let suiteErrors = [];
|
||||||
env.addReporter({
|
env.addReporter({
|
||||||
@@ -220,21 +197,9 @@ describe('Global error handling (integration)', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('routes unhandled exceptions to the running suite', async function() {
|
it('routes unhandled exceptions to the running suite', async function() {
|
||||||
const global = {
|
const global = mockGlobal();
|
||||||
...browserEventMethods(),
|
|
||||||
setTimeout: function(fn, delay) {
|
|
||||||
return setTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
clearTimeout: function(fn, delay) {
|
|
||||||
clearTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
queueMicrotask: function(fn) {
|
|
||||||
queueMicrotask(fn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
|
||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
env = new privateUnderTest.Env();
|
env = new privateUnderTest.Env({ global });
|
||||||
const reporter = jasmine.createSpyObj('fakeReporter', [
|
const reporter = jasmine.createSpyObj('fakeReporter', [
|
||||||
'specDone',
|
'specDone',
|
||||||
'suiteDone'
|
'suiteDone'
|
||||||
@@ -273,24 +238,12 @@ describe('Global error handling (integration)', function() {
|
|||||||
|
|
||||||
describe('When the most recently suite has reported suiteDone', function() {
|
describe('When the most recently suite has reported suiteDone', function() {
|
||||||
it('routes unhandled exceptions to an ancestor suite', async function() {
|
it('routes unhandled exceptions to an ancestor suite', async function() {
|
||||||
const global = {
|
const global = mockGlobal();
|
||||||
...browserEventMethods(),
|
const stackClearer = privateUnderTest.getStackClearer(global);
|
||||||
setTimeout: function(fn, delay) {
|
const realClearStack = stackClearer.clearStack;
|
||||||
return setTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
clearTimeout: function(fn, delay) {
|
|
||||||
clearTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
queueMicrotask: function(fn) {
|
|
||||||
queueMicrotask(fn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
|
||||||
|
|
||||||
const realClearStack = privateUnderTest.getClearStack(global);
|
|
||||||
const clearStackCallbacks = {};
|
const clearStackCallbacks = {};
|
||||||
let clearStackCallCount = 0;
|
let clearStackCallCount = 0;
|
||||||
spyOn(privateUnderTest, 'getClearStack').and.returnValue(function(fn) {
|
spyOn(stackClearer, 'clearStack').and.callFake(function(fn) {
|
||||||
clearStackCallCount++;
|
clearStackCallCount++;
|
||||||
|
|
||||||
if (clearStackCallbacks[clearStackCallCount]) {
|
if (clearStackCallbacks[clearStackCallCount]) {
|
||||||
@@ -299,9 +252,12 @@ describe('Global error handling (integration)', function() {
|
|||||||
|
|
||||||
realClearStack(fn);
|
realClearStack(fn);
|
||||||
});
|
});
|
||||||
|
spyOn(privateUnderTest, 'getStackClearer').and.returnValue(
|
||||||
|
stackClearer
|
||||||
|
);
|
||||||
|
|
||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
env = new privateUnderTest.Env();
|
env = new privateUnderTest.Env({ global });
|
||||||
|
|
||||||
let suiteErrors = [];
|
let suiteErrors = [];
|
||||||
env.addReporter({
|
env.addReporter({
|
||||||
@@ -341,21 +297,9 @@ describe('Global error handling (integration)', function() {
|
|||||||
|
|
||||||
describe('When the env has started reporting jasmineDone', function() {
|
describe('When the env has started reporting jasmineDone', function() {
|
||||||
it('logs the error to the console', async function() {
|
it('logs the error to the console', async function() {
|
||||||
const global = {
|
const global = mockGlobal();
|
||||||
...browserEventMethods(),
|
|
||||||
setTimeout: function(fn, delay) {
|
|
||||||
return setTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
clearTimeout: function(fn, delay) {
|
|
||||||
clearTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
queueMicrotask: function(fn) {
|
|
||||||
queueMicrotask(fn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
|
||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
env = new privateUnderTest.Env();
|
env = new privateUnderTest.Env({ global });
|
||||||
|
|
||||||
spyOn(console, 'error');
|
spyOn(console, 'error');
|
||||||
|
|
||||||
@@ -384,26 +328,14 @@ describe('Global error handling (integration)', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('routes all errors that occur during stack clearing somewhere', async function() {
|
it('routes all errors that occur during stack clearing somewhere', async function() {
|
||||||
const global = {
|
const global = mockGlobal();
|
||||||
...browserEventMethods(),
|
const stackClearer = privateUnderTest.getStackClearer(global);
|
||||||
setTimeout: function(fn, delay) {
|
const realClearStack = stackClearer.clearStack;
|
||||||
return setTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
clearTimeout: function(fn) {
|
|
||||||
clearTimeout(fn);
|
|
||||||
},
|
|
||||||
queueMicrotask: function(fn) {
|
|
||||||
queueMicrotask(fn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
|
||||||
|
|
||||||
const realClearStack = privateUnderTest.getClearStack(global);
|
|
||||||
let clearStackCallCount = 0;
|
let clearStackCallCount = 0;
|
||||||
let jasmineDone = false;
|
let jasmineDone = false;
|
||||||
const expectedErrors = [];
|
const expectedErrors = [];
|
||||||
const expectedErrorsAfterJasmineDone = [];
|
const expectedErrorsAfterJasmineDone = [];
|
||||||
spyOn(privateUnderTest, 'getClearStack').and.returnValue(function(fn) {
|
spyOn(stackClearer, 'clearStack').and.callFake(function(fn) {
|
||||||
clearStackCallCount++;
|
clearStackCallCount++;
|
||||||
const msg = `Error in clearStack #${clearStackCallCount}`;
|
const msg = `Error in clearStack #${clearStackCallCount}`;
|
||||||
|
|
||||||
@@ -416,10 +348,11 @@ describe('Global error handling (integration)', function() {
|
|||||||
dispatchErrorEvent(global, 'error', { error: msg });
|
dispatchErrorEvent(global, 'error', { error: msg });
|
||||||
realClearStack(fn);
|
realClearStack(fn);
|
||||||
});
|
});
|
||||||
|
spyOn(privateUnderTest, 'getStackClearer').and.returnValue(stackClearer);
|
||||||
spyOn(console, 'error');
|
spyOn(console, 'error');
|
||||||
|
|
||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
env = new privateUnderTest.Env();
|
env = new privateUnderTest.Env({ global });
|
||||||
|
|
||||||
const receivedErrors = [];
|
const receivedErrors = [];
|
||||||
function logErrors(event) {
|
function logErrors(event) {
|
||||||
@@ -459,21 +392,9 @@ describe('Global error handling (integration)', function() {
|
|||||||
|
|
||||||
describe('Handling unhandled promise rejections', function() {
|
describe('Handling unhandled promise rejections', function() {
|
||||||
it('routes unhandled promise rejections to the running spec', async function() {
|
it('routes unhandled promise rejections to the running spec', async function() {
|
||||||
const global = {
|
const global = mockGlobal();
|
||||||
...browserEventMethods(),
|
|
||||||
setTimeout: function(fn, delay) {
|
|
||||||
return setTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
clearTimeout: function(fn, delay) {
|
|
||||||
clearTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
queueMicrotask: function(fn) {
|
|
||||||
queueMicrotask(fn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
|
||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
env = new privateUnderTest.Env();
|
env = new privateUnderTest.Env({ global });
|
||||||
const reporter = jasmine.createSpyObj('fakeReporter', [
|
const reporter = jasmine.createSpyObj('fakeReporter', [
|
||||||
'specDone',
|
'specDone',
|
||||||
'suiteDone'
|
'suiteDone'
|
||||||
@@ -502,24 +423,12 @@ describe('Global error handling (integration)', function() {
|
|||||||
|
|
||||||
describe('When the most recently running spec has reported specDone', function() {
|
describe('When the most recently running spec has reported specDone', function() {
|
||||||
it('routes unhandled promise rejections to an ancestor suite', async function() {
|
it('routes unhandled promise rejections to an ancestor suite', async function() {
|
||||||
const global = {
|
const global = mockGlobal();
|
||||||
...browserEventMethods(),
|
const stackClearer = privateUnderTest.getStackClearer(global);
|
||||||
setTimeout: function(fn, delay) {
|
const realClearStack = stackClearer.clearStack;
|
||||||
return setTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
clearTimeout: function(fn) {
|
|
||||||
clearTimeout(fn);
|
|
||||||
},
|
|
||||||
queueMicrotask: function(fn) {
|
|
||||||
queueMicrotask(fn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
|
||||||
|
|
||||||
const realClearStack = privateUnderTest.getClearStack(global);
|
|
||||||
const clearStackCallbacks = {};
|
const clearStackCallbacks = {};
|
||||||
let clearStackCallCount = 0;
|
let clearStackCallCount = 0;
|
||||||
spyOn(privateUnderTest, 'getClearStack').and.returnValue(function(fn) {
|
spyOn(stackClearer, 'clearStack').and.callFake(function(fn) {
|
||||||
clearStackCallCount++;
|
clearStackCallCount++;
|
||||||
|
|
||||||
if (clearStackCallbacks[clearStackCallCount]) {
|
if (clearStackCallbacks[clearStackCallCount]) {
|
||||||
@@ -528,9 +437,12 @@ describe('Global error handling (integration)', function() {
|
|||||||
|
|
||||||
realClearStack(fn);
|
realClearStack(fn);
|
||||||
});
|
});
|
||||||
|
spyOn(privateUnderTest, 'getStackClearer').and.returnValue(
|
||||||
|
stackClearer
|
||||||
|
);
|
||||||
|
|
||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
env = new privateUnderTest.Env();
|
env = new privateUnderTest.Env({ global });
|
||||||
|
|
||||||
let suiteErrors = [];
|
let suiteErrors = [];
|
||||||
env.addReporter({
|
env.addReporter({
|
||||||
@@ -566,21 +478,9 @@ describe('Global error handling (integration)', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('routes unhandled promise rejections to the running suite', async function() {
|
it('routes unhandled promise rejections to the running suite', async function() {
|
||||||
const global = {
|
const global = mockGlobal();
|
||||||
...browserEventMethods(),
|
|
||||||
setTimeout: function(fn, delay) {
|
|
||||||
return setTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
clearTimeout: function(fn, delay) {
|
|
||||||
clearTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
queueMicrotask: function(fn) {
|
|
||||||
queueMicrotask(fn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
|
||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
env = new privateUnderTest.Env();
|
env = new privateUnderTest.Env({ global });
|
||||||
const reporter = jasmine.createSpyObj('fakeReporter', [
|
const reporter = jasmine.createSpyObj('fakeReporter', [
|
||||||
'specDone',
|
'specDone',
|
||||||
'suiteDone'
|
'suiteDone'
|
||||||
@@ -621,24 +521,12 @@ describe('Global error handling (integration)', function() {
|
|||||||
|
|
||||||
describe('When the most recently suite has reported suiteDone', function() {
|
describe('When the most recently suite has reported suiteDone', function() {
|
||||||
it('routes unhandled promise rejections to an ancestor suite', async function() {
|
it('routes unhandled promise rejections to an ancestor suite', async function() {
|
||||||
const global = {
|
const global = mockGlobal();
|
||||||
...browserEventMethods(),
|
const stackClearer = privateUnderTest.getStackClearer(global);
|
||||||
setTimeout: function(fn, delay) {
|
const realClearStack = stackClearer.clearStack;
|
||||||
return setTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
clearTimeout: function(fn, delay) {
|
|
||||||
clearTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
queueMicrotask: function(fn) {
|
|
||||||
queueMicrotask(fn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
|
||||||
|
|
||||||
const realClearStack = privateUnderTest.getClearStack(global);
|
|
||||||
const clearStackCallbacks = {};
|
const clearStackCallbacks = {};
|
||||||
let clearStackCallCount = 0;
|
let clearStackCallCount = 0;
|
||||||
spyOn(privateUnderTest, 'getClearStack').and.returnValue(function(fn) {
|
spyOn(stackClearer, 'clearStack').and.callFake(function(fn) {
|
||||||
clearStackCallCount++;
|
clearStackCallCount++;
|
||||||
|
|
||||||
if (clearStackCallbacks[clearStackCallCount]) {
|
if (clearStackCallbacks[clearStackCallCount]) {
|
||||||
@@ -647,9 +535,12 @@ describe('Global error handling (integration)', function() {
|
|||||||
|
|
||||||
realClearStack(fn);
|
realClearStack(fn);
|
||||||
});
|
});
|
||||||
|
spyOn(privateUnderTest, 'getStackClearer').and.returnValue(
|
||||||
|
stackClearer
|
||||||
|
);
|
||||||
|
|
||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
env = new privateUnderTest.Env();
|
env = new privateUnderTest.Env({ global });
|
||||||
|
|
||||||
let suiteErrors = [];
|
let suiteErrors = [];
|
||||||
env.addReporter({
|
env.addReporter({
|
||||||
@@ -689,21 +580,9 @@ describe('Global error handling (integration)', function() {
|
|||||||
|
|
||||||
describe('When the env has started reporting jasmineDone', function() {
|
describe('When the env has started reporting jasmineDone', function() {
|
||||||
it('logs the rejection to the console', async function() {
|
it('logs the rejection to the console', async function() {
|
||||||
const global = {
|
const global = mockGlobal();
|
||||||
...browserEventMethods(),
|
|
||||||
setTimeout: function(fn, delay) {
|
|
||||||
return setTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
clearTimeout: function(fn, delay) {
|
|
||||||
clearTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
queueMicrotask: function(fn) {
|
|
||||||
queueMicrotask(fn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
|
||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
env = new privateUnderTest.Env();
|
env = new privateUnderTest.Env({ global });
|
||||||
|
|
||||||
spyOn(console, 'error');
|
spyOn(console, 'error');
|
||||||
|
|
||||||
@@ -734,26 +613,14 @@ describe('Global error handling (integration)', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('routes all unhandled promise rejections that occur during stack clearing somewhere', async function() {
|
it('routes all unhandled promise rejections that occur during stack clearing somewhere', async function() {
|
||||||
const global = {
|
const global = mockGlobal();
|
||||||
...browserEventMethods(),
|
const stackClearer = privateUnderTest.getStackClearer(global);
|
||||||
setTimeout: function(fn, delay) {
|
const realClearStack = stackClearer.clearStack;
|
||||||
return setTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
clearTimeout: function(fn) {
|
|
||||||
clearTimeout(fn);
|
|
||||||
},
|
|
||||||
queueMicrotask: function(fn) {
|
|
||||||
queueMicrotask(fn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
|
||||||
|
|
||||||
const realClearStack = privateUnderTest.getClearStack(global);
|
|
||||||
let clearStackCallCount = 0;
|
let clearStackCallCount = 0;
|
||||||
let jasmineDone = false;
|
let jasmineDone = false;
|
||||||
const expectedErrors = [];
|
const expectedErrors = [];
|
||||||
const expectedErrorsAfterJasmineDone = [];
|
const expectedErrorsAfterJasmineDone = [];
|
||||||
spyOn(privateUnderTest, 'getClearStack').and.returnValue(function(fn) {
|
spyOn(stackClearer, 'clearStack').and.callFake(function(fn) {
|
||||||
clearStackCallCount++;
|
clearStackCallCount++;
|
||||||
const reason = `Error in clearStack #${clearStackCallCount}`;
|
const reason = `Error in clearStack #${clearStackCallCount}`;
|
||||||
const expectedMsg = `Unhandled promise rejection: ${reason} thrown`;
|
const expectedMsg = `Unhandled promise rejection: ${reason} thrown`;
|
||||||
@@ -767,10 +634,11 @@ describe('Global error handling (integration)', function() {
|
|||||||
dispatchErrorEvent(global, 'unhandledrejection', { reason });
|
dispatchErrorEvent(global, 'unhandledrejection', { reason });
|
||||||
realClearStack(fn);
|
realClearStack(fn);
|
||||||
});
|
});
|
||||||
|
spyOn(privateUnderTest, 'getStackClearer').and.returnValue(stackClearer);
|
||||||
spyOn(console, 'error');
|
spyOn(console, 'error');
|
||||||
|
|
||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
env = new privateUnderTest.Env();
|
env = new privateUnderTest.Env({ global });
|
||||||
|
|
||||||
const receivedErrors = [];
|
const receivedErrors = [];
|
||||||
function logErrors(event) {
|
function logErrors(event) {
|
||||||
@@ -819,21 +687,9 @@ describe('Global error handling (integration)', function() {
|
|||||||
let global, reporter;
|
let global, reporter;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
global = {
|
global = mockGlobal();
|
||||||
...browserEventMethods(),
|
|
||||||
setTimeout: function(fn, delay) {
|
|
||||||
return setTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
clearTimeout: function(fn, delay) {
|
|
||||||
clearTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
queueMicrotask: function(fn) {
|
|
||||||
queueMicrotask(fn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
|
||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
env = new privateUnderTest.Env();
|
env = new privateUnderTest.Env({ global });
|
||||||
env.configure({ detectLateRejectionHandling: true });
|
env.configure({ detectLateRejectionHandling: true });
|
||||||
|
|
||||||
reporter = jasmine.createSpyObj('fakeReporter', [
|
reporter = jasmine.createSpyObj('fakeReporter', [
|
||||||
@@ -966,21 +822,8 @@ describe('Global error handling (integration)', function() {
|
|||||||
|
|
||||||
describe("When the unhandled rejection event doesn't have a promise", function() {
|
describe("When the unhandled rejection event doesn't have a promise", function() {
|
||||||
it('reports the rejection', async function() {
|
it('reports the rejection', async function() {
|
||||||
const global = {
|
const global = mockGlobal();
|
||||||
...browserEventMethods(),
|
env = new privateUnderTest.Env({ global });
|
||||||
setTimeout: function(fn, delay) {
|
|
||||||
return setTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
clearTimeout: function(fn, delay) {
|
|
||||||
clearTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
queueMicrotask: function(fn) {
|
|
||||||
queueMicrotask(fn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
|
||||||
env.cleanup_();
|
|
||||||
env = new privateUnderTest.Env();
|
|
||||||
env.configure({ detectLateRejectionHandling: true });
|
env.configure({ detectLateRejectionHandling: true });
|
||||||
const reporter = jasmine.createSpyObj('fakeReporter', [
|
const reporter = jasmine.createSpyObj('fakeReporter', [
|
||||||
'specDone',
|
'specDone',
|
||||||
@@ -1012,21 +855,9 @@ describe('Global error handling (integration)', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('works when the suite is run multiple times', async function() {
|
it('works when the suite is run multiple times', async function() {
|
||||||
const global = {
|
const global = mockGlobal();
|
||||||
...browserEventMethods(),
|
|
||||||
setTimeout: function(fn, delay) {
|
|
||||||
return setTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
clearTimeout: function(fn, delay) {
|
|
||||||
clearTimeout(fn, delay);
|
|
||||||
},
|
|
||||||
queueMicrotask: function(fn) {
|
|
||||||
queueMicrotask(fn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
|
||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
env = new privateUnderTest.Env();
|
env = new privateUnderTest.Env({ global });
|
||||||
env.configure({ autoCleanClosures: false });
|
env.configure({ autoCleanClosures: false });
|
||||||
const reporter = jasmine.createSpyObj('fakeReporter', ['specDone']);
|
const reporter = jasmine.createSpyObj('fakeReporter', ['specDone']);
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ describe('The jasmine namespace', function() {
|
|||||||
'version',
|
'version',
|
||||||
|
|
||||||
// Asymmetric equality testers
|
// Asymmetric equality testers
|
||||||
|
'allOf',
|
||||||
'any',
|
'any',
|
||||||
'anything',
|
'anything',
|
||||||
'arrayContaining',
|
'arrayContaining',
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
(function() {
|
||||||
|
specHelpers.callerFilenameShim = function(fn) {
|
||||||
|
return fn();
|
||||||
|
};
|
||||||
|
})();
|
||||||
+235
-47
@@ -167,18 +167,18 @@ describe('HtmlReporterV2', function() {
|
|||||||
'.jasmine-alert .jasmine-bar'
|
'.jasmine-alert .jasmine-bar'
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(alertBars.length).toEqual(4);
|
expect(alertBars.length).toEqual(5);
|
||||||
expect(alertBars[1].innerHTML).toMatch(
|
expect(alertBars[2].innerHTML).toMatch(
|
||||||
/spec deprecation.*\(in spec: a spec with a deprecation\)/
|
/spec deprecation.*\(in spec: a spec with a deprecation\)/
|
||||||
);
|
);
|
||||||
expect(alertBars[1].getAttribute('class')).toEqual(
|
expect(alertBars[2].getAttribute('class')).toEqual(
|
||||||
'jasmine-bar jasmine-warning'
|
'jasmine-bar jasmine-warning'
|
||||||
);
|
);
|
||||||
expect(alertBars[2].innerHTML).toMatch(
|
expect(alertBars[3].innerHTML).toMatch(
|
||||||
/suite deprecation.*\(in suite: a suite with a deprecation\)/
|
/suite deprecation.*\(in suite: a suite with a deprecation\)/
|
||||||
);
|
);
|
||||||
expect(alertBars[3].innerHTML).toMatch(/global deprecation/);
|
expect(alertBars[4].innerHTML).toMatch(/global deprecation/);
|
||||||
expect(alertBars[3].innerHTML).not.toMatch(/in /);
|
expect(alertBars[4].innerHTML).not.toMatch(/in /);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays expandable stack traces', function() {
|
it('displays expandable stack traces', function() {
|
||||||
@@ -259,6 +259,214 @@ describe('HtmlReporterV2', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('The tab bar', function() {
|
||||||
|
function checkHidden(tabs, expected) {
|
||||||
|
const actual = Array.from(tabs).map(t =>
|
||||||
|
t.classList.contains('jasmine-hidden')
|
||||||
|
);
|
||||||
|
expect(actual)
|
||||||
|
.withContext('tab hiddenness')
|
||||||
|
.toEqual(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('while Jasmine is running', function() {
|
||||||
|
it('hides all tabs', function() {
|
||||||
|
const reporter = setup();
|
||||||
|
reporter.initialize();
|
||||||
|
reporter.jasmineStarted({ totalSpecsDefined: 0 });
|
||||||
|
const tabs = container.querySelectorAll('.jasmine-tab');
|
||||||
|
expect(tabs.length).toEqual(3);
|
||||||
|
expect(tabs[0].textContent).toEqual('Spec List');
|
||||||
|
expect(tabs[1].textContent).toEqual('Failures');
|
||||||
|
expect(tabs[2].textContent).toEqual('Performance');
|
||||||
|
checkHidden(tabs, [true, true, true]);
|
||||||
|
|
||||||
|
// Results, even failures, should not show any tabs
|
||||||
|
reporter.specDone({
|
||||||
|
id: 1,
|
||||||
|
description: 'a failing spec',
|
||||||
|
fullName: 'a failing spec',
|
||||||
|
status: 'failed',
|
||||||
|
failedExpectations: [{}],
|
||||||
|
passedExpectations: []
|
||||||
|
});
|
||||||
|
checkHidden(tabs, [true, true, true]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when Jasmine is done', function() {
|
||||||
|
function hasSpecOrSuiteFailureBehavior(reportEvents) {
|
||||||
|
let reporter;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
reporter = setup();
|
||||||
|
reporter.initialize();
|
||||||
|
reportEvents(reporter);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows all three tabs', function() {
|
||||||
|
const tabs = container.querySelectorAll('.jasmine-tab');
|
||||||
|
checkHidden(tabs, [false, false, false]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('selects the Failures tab', function() {
|
||||||
|
const reporterNode = container.querySelector(
|
||||||
|
'.jasmine_html-reporter'
|
||||||
|
);
|
||||||
|
expect(reporterNode).toHaveClass('jasmine-failure-list');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('switches between failure details and the spec summary', function() {
|
||||||
|
const tabs = container.querySelectorAll('.jasmine-tab');
|
||||||
|
let specListLink = () => tabs[0].querySelector('a');
|
||||||
|
let failuresLink = () => tabs[1].querySelector('a');
|
||||||
|
const reporterNode = container.querySelector(
|
||||||
|
'.jasmine_html-reporter'
|
||||||
|
);
|
||||||
|
expect(specListLink().textContent).toEqual('Spec List');
|
||||||
|
expect(failuresLink())
|
||||||
|
.withContext('failures link')
|
||||||
|
.toBeFalsy();
|
||||||
|
|
||||||
|
specListLink().click();
|
||||||
|
expect(reporterNode).toHaveClass('jasmine-spec-list');
|
||||||
|
expect(reporterNode).not.toHaveClass('jasmine-failure-list');
|
||||||
|
expect(specListLink())
|
||||||
|
.withContext('spec list link')
|
||||||
|
.toBeFalsy();
|
||||||
|
expect(failuresLink().textContent).toEqual('Failures');
|
||||||
|
|
||||||
|
failuresLink().click();
|
||||||
|
expect(reporterNode.getAttribute('class')).toMatch(
|
||||||
|
'jasmine-failure-list'
|
||||||
|
);
|
||||||
|
expect(failuresLink())
|
||||||
|
.withContext('failures link')
|
||||||
|
.toBeFalsy();
|
||||||
|
expect(specListLink().textContent).toEqual('Spec List');
|
||||||
|
expect(reporterNode).toHaveClass('jasmine-failure-list');
|
||||||
|
expect(reporterNode).not.toHaveClass('jasmine-spec-list');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasSpecAndSuiteSuccessBehavior(reportEvents) {
|
||||||
|
let reporter;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
reporter = setup();
|
||||||
|
reporter.initialize();
|
||||||
|
reportEvents(reporter);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows the Spec List and Performance tabs', function() {
|
||||||
|
const tabs = container.querySelectorAll('.jasmine-tab');
|
||||||
|
checkHidden(tabs, [false, true, false]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows the spec list view', function() {
|
||||||
|
const reporterNode = container.querySelector(
|
||||||
|
'.jasmine_html-reporter'
|
||||||
|
);
|
||||||
|
expect(reporterNode).toHaveClass('jasmine-spec-list');
|
||||||
|
expect(reporterNode).not.toHaveClass('jasmine-failure-list');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('with spec failures', function() {
|
||||||
|
hasSpecOrSuiteFailureBehavior(function(reporter) {
|
||||||
|
reporter.jasmineStarted({ totalSpecsDefined: 0 });
|
||||||
|
reporter.specDone({
|
||||||
|
id: 1,
|
||||||
|
description: 'a failing spec',
|
||||||
|
fullName: 'a failing spec',
|
||||||
|
status: 'failed',
|
||||||
|
failedExpectations: [{}],
|
||||||
|
passedExpectations: []
|
||||||
|
});
|
||||||
|
reporter.specDone({
|
||||||
|
id: 2,
|
||||||
|
description: 'a passing spec',
|
||||||
|
fullName: 'a passing spec',
|
||||||
|
status: 'passed',
|
||||||
|
failedExpectations: [],
|
||||||
|
passedExpectations: []
|
||||||
|
});
|
||||||
|
reporter.jasmineDone({});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with suite failures', function() {
|
||||||
|
hasSpecOrSuiteFailureBehavior(function(reporter) {
|
||||||
|
reporter.jasmineStarted({ totalSpecsDefined: 0 });
|
||||||
|
reporter.specDone({
|
||||||
|
id: 1,
|
||||||
|
description: 'a failing spec',
|
||||||
|
fullName: 'a failing spec',
|
||||||
|
status: 'failed',
|
||||||
|
failedExpectations: [{}],
|
||||||
|
passedExpectations: []
|
||||||
|
});
|
||||||
|
reporter.specDone({
|
||||||
|
id: 2,
|
||||||
|
description: 'a passing spec',
|
||||||
|
fullName: 'a passing spec',
|
||||||
|
status: 'passed',
|
||||||
|
failedExpectations: [],
|
||||||
|
passedExpectations: []
|
||||||
|
});
|
||||||
|
reporter.jasmineDone({});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('without any failures', function() {
|
||||||
|
hasSpecAndSuiteSuccessBehavior(function(reporter) {
|
||||||
|
reporter.jasmineStarted({ totalSpecsDefined: 0 });
|
||||||
|
reporter.specDone({
|
||||||
|
id: 1,
|
||||||
|
description: 'a passing spec',
|
||||||
|
fullName: 'a passing spec',
|
||||||
|
status: 'passed',
|
||||||
|
failedExpectations: [],
|
||||||
|
passedExpectations: []
|
||||||
|
});
|
||||||
|
reporter.suiteDone({ id: 1 });
|
||||||
|
reporter.jasmineDone({});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with only top suite failures', function() {
|
||||||
|
// Top suite failures are displayed in their own alert bars, so they
|
||||||
|
// don't cause the failures tab to be shown.
|
||||||
|
hasSpecAndSuiteSuccessBehavior(function(reporter) {
|
||||||
|
reporter.jasmineStarted({ totalSpecsDefined: 0 });
|
||||||
|
reporter.jasmineDone({
|
||||||
|
failedExpectations: [{}]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows the slow spec view when the Performance tab is clicked', function() {
|
||||||
|
const reporter = setup();
|
||||||
|
reporter.initialize();
|
||||||
|
reporter.jasmineStarted({ totalSpecsDefined: 0 });
|
||||||
|
reporter.specDone({
|
||||||
|
duration: 1.2,
|
||||||
|
failedExpectations: [],
|
||||||
|
passedExpectations: []
|
||||||
|
});
|
||||||
|
reporter.jasmineDone({});
|
||||||
|
const tabs = container.querySelectorAll('.jasmine-tab');
|
||||||
|
let perfLink = tabs[2].querySelector('a');
|
||||||
|
const reporterNode = container.querySelector('.jasmine_html-reporter');
|
||||||
|
expect(perfLink.textContent).toEqual('Performance');
|
||||||
|
perfLink.click();
|
||||||
|
expect(reporterNode).toHaveClass('jasmine-performance');
|
||||||
|
expect(reporterNode.innerHTML).toContain('<h2>Performance</h2>');
|
||||||
|
expect(reporterNode.innerHTML).toContain('<td>1.2ms</td>');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('when Jasmine is done', function() {
|
describe('when Jasmine is done', function() {
|
||||||
it('adds a warning to the link title of specs that have no expectations', function() {
|
it('adds a warning to the link title of specs that have no expectations', function() {
|
||||||
const reporter = setup();
|
const reporter = setup();
|
||||||
@@ -449,21 +657,18 @@ describe('HtmlReporterV2', function() {
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
const alertBars = container.querySelectorAll(
|
const errorBars = container.querySelectorAll(
|
||||||
'.jasmine-alert .jasmine-bar'
|
'.jasmine-alert .jasmine-bar.jasmine-errored'
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(alertBars.length).toEqual(3);
|
expect(errorBars.length).toEqual(2);
|
||||||
expect(alertBars[1].getAttribute('class')).toEqual(
|
expect(errorBars[0].innerHTML).toMatch(
|
||||||
'jasmine-bar jasmine-errored'
|
|
||||||
);
|
|
||||||
expect(alertBars[1].innerHTML).toMatch(
|
|
||||||
/AfterAll Global After All Failure/
|
/AfterAll Global After All Failure/
|
||||||
);
|
);
|
||||||
expect(alertBars[2].innerHTML).toMatch(
|
expect(errorBars[1].innerHTML).toMatch(
|
||||||
/Error during loading: Your JS is borken/
|
/Error during loading: Your JS is borken/
|
||||||
);
|
);
|
||||||
expect(alertBars[2].innerHTML).not.toMatch(/line/);
|
expect(errorBars[1].innerHTML).not.toMatch(/line/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not display the "AfterAll" prefix for other error types', function() {
|
it('does not display the "AfterAll" prefix for other error types', function() {
|
||||||
@@ -482,16 +687,16 @@ describe('HtmlReporterV2', function() {
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
const alertBars = container.querySelectorAll(
|
const errorBars = container.querySelectorAll(
|
||||||
'.jasmine-alert .jasmine-bar'
|
'.jasmine-alert .jasmine-bar.jasmine-errored'
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(alertBars.length).toEqual(4);
|
expect(errorBars.length).toEqual(3);
|
||||||
expect(alertBars[1].textContent).toContain('load error');
|
expect(errorBars[0].textContent).toContain('load error');
|
||||||
expect(alertBars[2].textContent).toContain('lateExpectation error');
|
expect(errorBars[1].textContent).toContain('lateExpectation error');
|
||||||
expect(alertBars[3].textContent).toContain('lateError error');
|
expect(errorBars[2].textContent).toContain('lateError error');
|
||||||
|
|
||||||
for (let bar of alertBars) {
|
for (let bar of errorBars) {
|
||||||
expect(bar.textContent).not.toContain('AfterAll');
|
expect(bar.textContent).not.toContain('AfterAll');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -512,12 +717,12 @@ describe('HtmlReporterV2', function() {
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
const alertBars = container.querySelectorAll(
|
const alertBar = container.querySelector(
|
||||||
'.jasmine-alert .jasmine-bar'
|
'.jasmine-alert .jasmine-bar.jasmine-errored'
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(alertBars.length).toEqual(2);
|
expect(alertBar).toBeTruthy();
|
||||||
expect(alertBars[1].innerHTML).toMatch(
|
expect(alertBar.innerHTML).toMatch(
|
||||||
/Error during loading: Your JS is borken in some\/file.js line 42/
|
/Error during loading: Your JS is borken in some\/file.js line 42/
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -758,12 +963,12 @@ describe('HtmlReporterV2', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('reports the specs counts', function() {
|
it('reports the specs counts', function() {
|
||||||
const alertBars = container.querySelectorAll(
|
const resultBar = container.querySelector(
|
||||||
'.jasmine-alert .jasmine-bar'
|
'.jasmine-alert .jasmine-bar.jasmine-overall-result'
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(alertBars.length).toEqual(1);
|
expect(resultBar).toBeTruthy();
|
||||||
expect(alertBars[0].innerHTML).toMatch(/2 specs, 0 failures/);
|
expect(resultBar.innerHTML).toMatch(/2 specs, 0 failures/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('reports no failure details', function() {
|
it('reports no failure details', function() {
|
||||||
@@ -1072,23 +1277,6 @@ describe('HtmlReporterV2', function() {
|
|||||||
)}`
|
)}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows switching between failure details and the spec summary', function() {
|
|
||||||
const menuBar = container.querySelectorAll('.jasmine-bar')[1];
|
|
||||||
|
|
||||||
expect(menuBar.getAttribute('class')).not.toMatch(/hidden/);
|
|
||||||
|
|
||||||
const link = menuBar.querySelector('a');
|
|
||||||
expect(link.innerHTML).toEqual('Failures');
|
|
||||||
expect(link.getAttribute('href')).toEqual('#');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sets the reporter to 'Failures List' mode", function() {
|
|
||||||
const reporterNode = container.querySelector('.jasmine_html-reporter');
|
|
||||||
expect(reporterNode.getAttribute('class')).toMatch(
|
|
||||||
'jasmine-failure-list'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('counts failures that are reported in the jasmineDone event', function() {
|
it('counts failures that are reported in the jasmineDone event', function() {
|
||||||
|
|||||||
@@ -1,48 +1,69 @@
|
|||||||
describe('HtmlSpecFilterV2', function() {
|
describe('HtmlSpecFilterV2', function() {
|
||||||
it('matches everything when no string is provided', function() {
|
describe('When both query parameters are falsy', function() {
|
||||||
const specFilter = new privateUnderTest.HtmlSpecFilterV2({
|
it('matches everything', function() {
|
||||||
filterString() {
|
const specFilter = new privateUnderTest.HtmlSpecFilterV2({
|
||||||
return '';
|
filterParams() {
|
||||||
}
|
return { path: '', spec: '' };
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
expect(specFilter.matches({})).toBeTrue();
|
expect(specFilter.matches({})).toBeTrue();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('matches a spec with the exact same path', function() {
|
describe('When the path parameter is truthy', function() {
|
||||||
const specFilter = new privateUnderTest.HtmlSpecFilterV2({
|
it('matches a spec with the exact same path', function() {
|
||||||
filterString() {
|
const specFilter = new privateUnderTest.HtmlSpecFilterV2({
|
||||||
return '["a","b","c"]';
|
filterParams() {
|
||||||
}
|
return { path: '["a","b","c"]', spec: '' };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(specFilter.matches(stubSpec(['a', 'b', 'c']))).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(specFilter.matches(stubSpec(['a', 'b', 'c']))).toBeTrue();
|
it('matches a spec whose path has the filter path as a prefix', function() {
|
||||||
});
|
const specFilter = new privateUnderTest.HtmlSpecFilterV2({
|
||||||
|
filterParams() {
|
||||||
|
return { path: '["a","b"]', spec: '' };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('matches a spec whose path has the filter path as a prefix', function() {
|
expect(specFilter.matches(stubSpec(['a', 'b', 'c']))).toBeTrue();
|
||||||
const specFilter = new privateUnderTest.HtmlSpecFilterV2({
|
|
||||||
filterString() {
|
|
||||||
return '["a","b"]';
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(specFilter.matches(stubSpec(['a', 'b', 'c']))).toBeTrue();
|
it('does not match a spec with a different path', function() {
|
||||||
});
|
const specFilter = new privateUnderTest.HtmlSpecFilterV2({
|
||||||
|
filterParams() {
|
||||||
|
return { path: '["a","b","c"]', spec: '' };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('does not match a spec with a different path', function() {
|
expect(specFilter.matches(stubSpec(['a', 'd', 'c']))).toBeFalse();
|
||||||
const specFilter = new privateUnderTest.HtmlSpecFilterV2({
|
|
||||||
filterString() {
|
|
||||||
return '["a","b","c"]';
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(specFilter.matches(stubSpec(['a', 'd', 'c']))).toBeFalse();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function stubSpec(path) {
|
describe('When the path parameter is falsy and the spec parameter is truthy', function() {
|
||||||
|
it('matches specs with full names containing the parameter value', function() {
|
||||||
|
const specFilter = new privateUnderTest.HtmlSpecFilterV2({
|
||||||
|
filterParams() {
|
||||||
|
return { path: '', spec: 'bar' };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(specFilter.matches(stubSpec('', 'foo bar baz'))).toBeTrue();
|
||||||
|
expect(specFilter.matches(stubSpec('', 'foo baz'))).toBeFalse();
|
||||||
|
expect(specFilter.matches(stubSpec('', 'sandbars'))).toBeTrue();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function stubSpec(path, fullName) {
|
||||||
return {
|
return {
|
||||||
getPath() {
|
getPath() {
|
||||||
return path;
|
return path;
|
||||||
|
},
|
||||||
|
getFullName() {
|
||||||
|
return fullName;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
describe('PerformanceView', function() {
|
||||||
|
it('shows specs ordered by execution time', function() {
|
||||||
|
const stateBuilder = new privateUnderTest.ResultsStateBuilder();
|
||||||
|
stateBuilder.suiteStarted({});
|
||||||
|
stateBuilder.specDone({
|
||||||
|
fullName: 'spec A',
|
||||||
|
duration: 2
|
||||||
|
});
|
||||||
|
stateBuilder.suiteDone({});
|
||||||
|
stateBuilder.specDone({
|
||||||
|
fullName: 'spec B',
|
||||||
|
duration: 1
|
||||||
|
});
|
||||||
|
stateBuilder.specDone({
|
||||||
|
fullName: 'spec C',
|
||||||
|
duration: 3
|
||||||
|
});
|
||||||
|
const subject = new privateUnderTest.PerformanceView();
|
||||||
|
subject.addResults(stateBuilder.topResults);
|
||||||
|
|
||||||
|
const rows = Array.from(subject.rootEl.querySelectorAll('tbody tr'));
|
||||||
|
const durations = rows.map(r => r.querySelectorAll('td')[0].textContent);
|
||||||
|
const names = rows.map(r => r.querySelectorAll('td')[1].textContent);
|
||||||
|
expect(names).toEqual(['spec C', 'spec A', 'spec B']);
|
||||||
|
expect(durations).toEqual(['3ms', '2ms', '1ms']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows at most 20 specs', function() {
|
||||||
|
const stateBuilder = new privateUnderTest.ResultsStateBuilder();
|
||||||
|
const subject = new privateUnderTest.PerformanceView();
|
||||||
|
|
||||||
|
for (let i = 0; i < 21; i++) {
|
||||||
|
stateBuilder.specDone({
|
||||||
|
fullName: `spec ${i}`,
|
||||||
|
duration: i
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
subject.addResults(stateBuilder.topResults);
|
||||||
|
|
||||||
|
expect(subject.rootEl.querySelectorAll('tbody tr').length).toEqual(20);
|
||||||
|
expect(subject.textContent).not.toContain('spec 0');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows mean and median run times for an odd number of specs', function() {
|
||||||
|
const stateBuilder = new privateUnderTest.ResultsStateBuilder();
|
||||||
|
const subject = new privateUnderTest.PerformanceView();
|
||||||
|
|
||||||
|
stateBuilder.specDone({ duration: 1 });
|
||||||
|
stateBuilder.specDone({ duration: 2 });
|
||||||
|
stateBuilder.specDone({ duration: 5 });
|
||||||
|
subject.addResults(stateBuilder.topResults);
|
||||||
|
|
||||||
|
expect(subject.rootEl.textContent).toContain('Mean spec run time: 3ms');
|
||||||
|
expect(subject.rootEl.textContent).toContain('Median spec run time: 2ms');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows mean and median run times for an even number of specs', function() {
|
||||||
|
const stateBuilder = new privateUnderTest.ResultsStateBuilder();
|
||||||
|
const subject = new privateUnderTest.PerformanceView();
|
||||||
|
|
||||||
|
stateBuilder.specDone({ duration: 1 });
|
||||||
|
stateBuilder.specDone({ duration: 3 });
|
||||||
|
stateBuilder.specDone({ duration: 10 });
|
||||||
|
stateBuilder.specDone({ duration: 2 });
|
||||||
|
subject.addResults(stateBuilder.topResults);
|
||||||
|
|
||||||
|
expect(subject.rootEl.textContent).toContain('Mean spec run time: 4ms');
|
||||||
|
expect(subject.rootEl.textContent).toContain('Median spec run time: 2ms');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('copes with 0 specs', function() {
|
||||||
|
const stateBuilder = new privateUnderTest.ResultsStateBuilder();
|
||||||
|
const subject = new privateUnderTest.PerformanceView();
|
||||||
|
|
||||||
|
expect(function() {
|
||||||
|
subject.addResults(stateBuilder.topResults);
|
||||||
|
}).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('filters out excluded specs', function() {
|
||||||
|
const stateBuilder = new privateUnderTest.ResultsStateBuilder();
|
||||||
|
stateBuilder.specDone({
|
||||||
|
fullName: 'spec A',
|
||||||
|
duration: 2
|
||||||
|
});
|
||||||
|
stateBuilder.specDone({
|
||||||
|
fullName: 'spec B',
|
||||||
|
duration: 1,
|
||||||
|
status: 'excluded'
|
||||||
|
});
|
||||||
|
stateBuilder.specDone({
|
||||||
|
fullName: 'spec C',
|
||||||
|
duration: 3
|
||||||
|
});
|
||||||
|
const subject = new privateUnderTest.PerformanceView();
|
||||||
|
subject.addResults(stateBuilder.topResults);
|
||||||
|
|
||||||
|
const rows = Array.from(subject.rootEl.querySelectorAll('tbody tr'));
|
||||||
|
const names = rows.map(r => r.querySelectorAll('td')[1].textContent);
|
||||||
|
expect(names).toEqual(['spec C', 'spec A']);
|
||||||
|
expect(subject.rootEl.textContent).toContain('Mean spec run time: 3ms');
|
||||||
|
expect(subject.rootEl.textContent).toContain('Median spec run time: 2ms');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
describe('TabBar', function() {
|
||||||
|
it('initially renders but hides the tabs', function() {
|
||||||
|
const subject = new privateUnderTest.TabBar([
|
||||||
|
{ id: 'tab1', label: 'tab 1' }
|
||||||
|
]);
|
||||||
|
const tabs = subject.rootEl.querySelectorAll('.jasmine-tab');
|
||||||
|
expect(tabs.length).toEqual(1);
|
||||||
|
expect(tabs[0].id).toEqual('tab1');
|
||||||
|
expect(tabs[0]).toHaveClass('jasmine-hidden');
|
||||||
|
const link = tabs[0].querySelector('a');
|
||||||
|
expect(link).toBeTruthy();
|
||||||
|
expect(link.textContent).toEqual('tab 1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not initially call the onSelect callback', function() {
|
||||||
|
const onSelect = jasmine.createSpy('onSelect');
|
||||||
|
new privateUnderTest.TabBar([{ id: 'tab1', label: '' }], onSelect);
|
||||||
|
expect(onSelect).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#showTab', function() {
|
||||||
|
it('shows the specified tab', function() {
|
||||||
|
const subject = new privateUnderTest.TabBar([
|
||||||
|
{ id: 'tab1' },
|
||||||
|
{ id: 'tab2' }
|
||||||
|
]);
|
||||||
|
|
||||||
|
subject.showTab('tab2');
|
||||||
|
|
||||||
|
const tabs = subject.rootEl.querySelectorAll('.jasmine-tab');
|
||||||
|
expect(tabs[0]).toHaveClass('jasmine-hidden');
|
||||||
|
expect(tabs[1]).not.toHaveClass('jasmine-hidden');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not hide previously shown tabs', function() {
|
||||||
|
const subject = new privateUnderTest.TabBar([
|
||||||
|
{ id: 'tab1' },
|
||||||
|
{ id: 'tab2' }
|
||||||
|
]);
|
||||||
|
|
||||||
|
subject.showTab('tab1');
|
||||||
|
subject.showTab('tab2');
|
||||||
|
|
||||||
|
const tabs = subject.rootEl.querySelectorAll('.jasmine-tab');
|
||||||
|
expect(tabs[0]).not.toHaveClass('jasmine-hidden');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("When a tab's link is clicked", function() {
|
||||||
|
it("calls the onSelect callback with the tab's id", function() {
|
||||||
|
const onSelect = jasmine.createSpy('onSelect');
|
||||||
|
const subject = new privateUnderTest.TabBar(
|
||||||
|
[{ id: 'tab1', label: '' }],
|
||||||
|
onSelect
|
||||||
|
);
|
||||||
|
|
||||||
|
subject.rootEl.querySelector('.jasmine-tab a').click();
|
||||||
|
|
||||||
|
expect(onSelect).toHaveBeenCalledWith('tab1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows links on all non-selected tabs only', function() {
|
||||||
|
const subject = new privateUnderTest.TabBar(
|
||||||
|
[
|
||||||
|
{ id: 'tab1', label: 'tab 1' },
|
||||||
|
{ id: 'tab2', label: 'tab 2' },
|
||||||
|
{ id: 'tab3', label: 'tab 3' }
|
||||||
|
],
|
||||||
|
() => {}
|
||||||
|
);
|
||||||
|
|
||||||
|
subject.rootEl.querySelectorAll('.jasmine-tab a')[1].click();
|
||||||
|
let tabs = subject.rootEl.querySelectorAll('.jasmine-tab');
|
||||||
|
expect(tabs[0].querySelector('a'))
|
||||||
|
.withContext('tab 1')
|
||||||
|
.toBeTruthy();
|
||||||
|
expect(tabs[1].querySelector('a'))
|
||||||
|
.withContext('tab 1')
|
||||||
|
.toBeFalsy();
|
||||||
|
expect(tabs[2].querySelector('a'))
|
||||||
|
.withContext('tab 1')
|
||||||
|
.toBeTruthy();
|
||||||
|
|
||||||
|
subject.rootEl.querySelectorAll('.jasmine-tab a')[0].click();
|
||||||
|
tabs = subject.rootEl.querySelectorAll('.jasmine-tab');
|
||||||
|
expect(tabs[0].querySelector('a'))
|
||||||
|
.withContext('tab 1')
|
||||||
|
.toBeFalsy();
|
||||||
|
expect(tabs[1].querySelector('a'))
|
||||||
|
.withContext('tab 1')
|
||||||
|
.toBeTruthy();
|
||||||
|
expect(tabs[2].querySelector('a'))
|
||||||
|
.withContext('tab 1')
|
||||||
|
.toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -23,11 +23,13 @@ module.exports = {
|
|||||||
'helpers/BrowserFlags.js',
|
'helpers/BrowserFlags.js',
|
||||||
'helpers/domHelpers.js',
|
'helpers/domHelpers.js',
|
||||||
'helpers/integrationMatchers.js',
|
'helpers/integrationMatchers.js',
|
||||||
|
'helpers/callerFilenameShim.js',
|
||||||
'helpers/defineJasmineUnderTest.js',
|
'helpers/defineJasmineUnderTest.js',
|
||||||
'helpers/resetEnv.js'
|
'helpers/resetEnv.js'
|
||||||
],
|
],
|
||||||
env: {
|
env: {
|
||||||
forbidDuplicateNames: true
|
forbidDuplicateNames: true,
|
||||||
|
safariYieldStrategy: 'time'
|
||||||
},
|
},
|
||||||
random: true,
|
random: true,
|
||||||
browser: {
|
browser: {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
"helpers/init.js",
|
"helpers/init.js",
|
||||||
"helpers/domHelpers.js",
|
"helpers/domHelpers.js",
|
||||||
"helpers/integrationMatchers.js",
|
"helpers/integrationMatchers.js",
|
||||||
|
"helpers/callerFilenameShim.js",
|
||||||
"helpers/overrideConsoleLogForCircleCi.js",
|
"helpers/overrideConsoleLogForCircleCi.js",
|
||||||
"helpers/nodeDefineJasmineUnderTest.js",
|
"helpers/nodeDefineJasmineUnderTest.js",
|
||||||
"helpers/resetEnv.js"
|
"helpers/resetEnv.js"
|
||||||
|
|||||||
@@ -34,6 +34,12 @@
|
|||||||
*/
|
*/
|
||||||
env.addReporter(jsApiReporter);
|
env.addReporter(jsApiReporter);
|
||||||
env.addReporter(htmlReporter);
|
env.addReporter(htmlReporter);
|
||||||
|
/**
|
||||||
|
* Configures Jasmine based on the current set of query parameters. This
|
||||||
|
* supports all parameters set by the HTML reporter as well as
|
||||||
|
* spec=partialPath, which filters out specs whose paths don't contain the
|
||||||
|
* parameter.
|
||||||
|
*/
|
||||||
env.configure(urls.configFromCurrentUrl());
|
env.configure(urls.configFromCurrentUrl());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -128,7 +128,45 @@ getJasmineRequireObj().Configuration = function(j$) {
|
|||||||
* @type Boolean
|
* @type Boolean
|
||||||
* @default false
|
* @default false
|
||||||
*/
|
*/
|
||||||
detectLateRejectionHandling: false
|
detectLateRejectionHandling: false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of extra stack frames inserted by a wrapper around {@link it}
|
||||||
|
* or by some other local modification. Jasmine uses this to determine the
|
||||||
|
* filename for {@link SpecStartedEvent} and {@link SpecDoneEvent}.
|
||||||
|
* @name Configuration#extraItStackFrames
|
||||||
|
* @since 5.13.0
|
||||||
|
* @type number
|
||||||
|
* @default 0
|
||||||
|
*/
|
||||||
|
extraItStackFrames: 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of extra stack frames inserted by a wrapper around
|
||||||
|
* {@link describe} or by some other local modification. Jasmine uses this
|
||||||
|
* to determine the filename for {@link SpecStartedEvent} and
|
||||||
|
* {@link SpecDoneEvent}.
|
||||||
|
* @name Configuration#extraDescribeStackFrames
|
||||||
|
* @since 5.13.0
|
||||||
|
* @type number
|
||||||
|
* @default 0
|
||||||
|
*/
|
||||||
|
extraDescribeStackFrames: 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The strategy to use in Safari and similar browsers to determine how often
|
||||||
|
* to yield control by calling setTimeout. If set to "count", the default,
|
||||||
|
* the frequency of setTimeout calls is based on the number of relevant
|
||||||
|
* function calls. If set to "time", the frequency of setTimeout calls is
|
||||||
|
* based on elapsed time. Using "time" may provide a significant performance
|
||||||
|
* improvement, but as of 6.0 it hasn't been tested with a wide variety of
|
||||||
|
* workloads and should be considered experimental.
|
||||||
|
* @name Configuration#safariYieldStrategy
|
||||||
|
* @since 6.0.0
|
||||||
|
* @type 'count' | 'time'
|
||||||
|
* @default 'count'
|
||||||
|
*/
|
||||||
|
safariYieldStrategy: 'count'
|
||||||
};
|
};
|
||||||
Object.freeze(defaultConfig);
|
Object.freeze(defaultConfig);
|
||||||
|
|
||||||
@@ -179,6 +217,28 @@ getJasmineRequireObj().Configuration = function(j$) {
|
|||||||
if (typeof changes.seed !== 'undefined') {
|
if (typeof changes.seed !== 'undefined') {
|
||||||
this.#values.seed = changes.seed;
|
this.#values.seed = changes.seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 0 is a valid value for both of these, so a truthiness check wouldn't work
|
||||||
|
if (typeof changes.extraItStackFrames !== 'undefined') {
|
||||||
|
this.#values.extraItStackFrames = changes.extraItStackFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof changes.extraDescribeStackFrames !== 'undefined') {
|
||||||
|
this.#values.extraDescribeStackFrames =
|
||||||
|
changes.extraDescribeStackFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof changes.safariYieldStrategy !== 'undefined') {
|
||||||
|
const v = changes.safariYieldStrategy;
|
||||||
|
|
||||||
|
if (v === 'count' || v === 'time') {
|
||||||
|
this.#values.safariYieldStrategy = v;
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
"Invalid safariYieldStrategy value. Valid values are 'count' and 'time'."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+25
-13
@@ -1,6 +1,8 @@
|
|||||||
getJasmineRequireObj().Env = function(j$) {
|
getJasmineRequireObj().Env = function(j$) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const DEFAULT_IT_DESCRIBE_STACK_DEPTH = 3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class Env
|
* @class Env
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
@@ -18,7 +20,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
|
|
||||||
const realSetTimeout = global.setTimeout;
|
const realSetTimeout = global.setTimeout;
|
||||||
const realClearTimeout = global.clearTimeout;
|
const realClearTimeout = global.clearTimeout;
|
||||||
const clearStack = j$.private.getClearStack(global);
|
const stackClearer = j$.private.getStackClearer(global);
|
||||||
this.clock = new j$.private.Clock(
|
this.clock = new j$.private.Clock(
|
||||||
global,
|
global,
|
||||||
function() {
|
function() {
|
||||||
@@ -28,7 +30,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const globalErrors = new GlobalErrors(
|
const globalErrors = new GlobalErrors(
|
||||||
undefined,
|
global,
|
||||||
// Configuration is late-bound because GlobalErrors needs to be constructed
|
// Configuration is late-bound because GlobalErrors needs to be constructed
|
||||||
// before it's set to detect load-time errors in browsers
|
// before it's set to detect load-time errors in browsers
|
||||||
() => this.configuration()
|
() => this.configuration()
|
||||||
@@ -97,6 +99,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
|
|
||||||
config.update(changes);
|
config.update(changes);
|
||||||
deprecator.verboseDeprecations(config.verboseDeprecations);
|
deprecator.verboseDeprecations(config.verboseDeprecations);
|
||||||
|
stackClearer.setSafariYieldStrategy(config.safariYieldStrategy);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -299,7 +302,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function runQueue(options) {
|
function runQueue(options) {
|
||||||
options.clearStack = options.clearStack || clearStack;
|
options.clearStack = options.clearStack || stackClearer;
|
||||||
options.timeout = {
|
options.timeout = {
|
||||||
setTimeout: realSetTimeout,
|
setTimeout: realSetTimeout,
|
||||||
clearTimeout: realClearTimeout
|
clearTimeout: realClearTimeout
|
||||||
@@ -591,14 +594,14 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
|
|
||||||
this.describe = function(description, definitionFn) {
|
this.describe = function(description, definitionFn) {
|
||||||
ensureIsNotNested('describe');
|
ensureIsNotNested('describe');
|
||||||
const filename = callerCallerFilename();
|
const filename = indirectCallerFilename(describeStackDepth());
|
||||||
return suiteBuilder.describe(description, definitionFn, filename)
|
return suiteBuilder.describe(description, definitionFn, filename)
|
||||||
.metadata;
|
.metadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.xdescribe = function(description, definitionFn) {
|
this.xdescribe = function(description, definitionFn) {
|
||||||
ensureIsNotNested('xdescribe');
|
ensureIsNotNested('xdescribe');
|
||||||
const filename = callerCallerFilename();
|
const filename = indirectCallerFilename(describeStackDepth());
|
||||||
return suiteBuilder.xdescribe(description, definitionFn, filename)
|
return suiteBuilder.xdescribe(description, definitionFn, filename)
|
||||||
.metadata;
|
.metadata;
|
||||||
};
|
};
|
||||||
@@ -606,30 +609,38 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
this.fdescribe = function(description, definitionFn) {
|
this.fdescribe = function(description, definitionFn) {
|
||||||
ensureIsNotNested('fdescribe');
|
ensureIsNotNested('fdescribe');
|
||||||
ensureNonParallel('fdescribe');
|
ensureNonParallel('fdescribe');
|
||||||
const filename = callerCallerFilename();
|
const filename = indirectCallerFilename(describeStackDepth());
|
||||||
return suiteBuilder.fdescribe(description, definitionFn, filename)
|
return suiteBuilder.fdescribe(description, definitionFn, filename)
|
||||||
.metadata;
|
.metadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.it = function(description, fn, timeout) {
|
this.it = function(description, fn, timeout) {
|
||||||
ensureIsNotNested('it');
|
ensureIsNotNested('it');
|
||||||
const filename = callerCallerFilename();
|
const filename = indirectCallerFilename(itStackDepth());
|
||||||
return suiteBuilder.it(description, fn, timeout, filename).metadata;
|
return suiteBuilder.it(description, fn, timeout, filename).metadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.xit = function(description, fn, timeout) {
|
this.xit = function(description, fn, timeout) {
|
||||||
ensureIsNotNested('xit');
|
ensureIsNotNested('xit');
|
||||||
const filename = callerCallerFilename();
|
const filename = indirectCallerFilename(itStackDepth());
|
||||||
return suiteBuilder.xit(description, fn, timeout, filename).metadata;
|
return suiteBuilder.xit(description, fn, timeout, filename).metadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.fit = function(description, fn, timeout) {
|
this.fit = function(description, fn, timeout) {
|
||||||
ensureIsNotNested('fit');
|
ensureIsNotNested('fit');
|
||||||
ensureNonParallel('fit');
|
ensureNonParallel('fit');
|
||||||
const filename = callerCallerFilename();
|
const filename = indirectCallerFilename(itStackDepth());
|
||||||
return suiteBuilder.fit(description, fn, timeout, filename).metadata;
|
return suiteBuilder.fit(description, fn, timeout, filename).metadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function itStackDepth() {
|
||||||
|
return DEFAULT_IT_DESCRIBE_STACK_DEPTH + config.extraItStackFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
function describeStackDepth() {
|
||||||
|
return DEFAULT_IT_DESCRIBE_STACK_DEPTH + config.extraDescribeStackFrames;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a user-defined property as part of the properties field of {@link SpecDoneEvent}
|
* Get a user-defined property as part of the properties field of {@link SpecDoneEvent}
|
||||||
* @name Env#getSpecProperty
|
* @name Env#getSpecProperty
|
||||||
@@ -815,11 +826,12 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function callerCallerFilename() {
|
function indirectCallerFilename(depth) {
|
||||||
const frames = new j$.private.StackTrace(new Error()).frames;
|
const frames = new j$.private.StackTrace(new Error()).frames;
|
||||||
// frames[3] should always exist except in Jasmine's own tests, which bypass
|
// The specified frame should always exist except in Jasmine's own tests,
|
||||||
// the global it/describe layer, but don't crash if it doesn't.
|
// which bypass the global it/describe layer, but could be absent in case
|
||||||
return frames[3] && frames[3].file;
|
// of misconfiguration. Don't crash if it's absent.
|
||||||
|
return frames[depth] && frames[depth].file;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Env;
|
return Env;
|
||||||
|
|||||||
@@ -51,11 +51,11 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.onComplete = attrs.onComplete || emptyFn;
|
this.onComplete = attrs.onComplete || emptyFn;
|
||||||
this.clearStack =
|
this.clearStack = attrs.clearStack || {
|
||||||
attrs.clearStack ||
|
clearStack(fn) {
|
||||||
function(fn) {
|
|
||||||
fn();
|
fn();
|
||||||
};
|
}
|
||||||
|
};
|
||||||
this.onException = attrs.onException || emptyFn;
|
this.onException = attrs.onException || emptyFn;
|
||||||
this.onMultipleDone = attrs.onMultipleDone || fallbackOnMultipleDone;
|
this.onMultipleDone = attrs.onMultipleDone || fallbackOnMultipleDone;
|
||||||
this.userContext = attrs.userContext || new j$.private.UserContext();
|
this.userContext = attrs.userContext || new j$.private.UserContext();
|
||||||
@@ -235,7 +235,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.clearStack(() => {
|
this.clearStack.clearStack(() => {
|
||||||
this.globalErrors.popListener(this.handleFinalError);
|
this.globalErrors.popListener(this.handleFinalError);
|
||||||
|
|
||||||
if (this.errored_) {
|
if (this.errored_) {
|
||||||
|
|||||||
+21
-6
@@ -72,8 +72,11 @@ getJasmineRequireObj().Spec = function(j$) {
|
|||||||
// Key and value will eventually be cloned during reporting. The error
|
// Key and value will eventually be cloned during reporting. The error
|
||||||
// thrown at that point if they aren't cloneable isn't very helpful.
|
// thrown at that point if they aren't cloneable isn't very helpful.
|
||||||
// Throw a better one now.
|
// Throw a better one now.
|
||||||
j$.private.util.assertReporterCloneable(key, 'Key');
|
if (!j$.private.isString(key)) {
|
||||||
|
throw new Error('Key must be a string');
|
||||||
|
}
|
||||||
j$.private.util.assertReporterCloneable(value, 'Value');
|
j$.private.util.assertReporterCloneable(value, 'Value');
|
||||||
|
|
||||||
this.#executionState.properties = this.#executionState.properties || {};
|
this.#executionState.properties = this.#executionState.properties || {};
|
||||||
this.#executionState.properties[key] = value;
|
this.#executionState.properties[key] = value;
|
||||||
}
|
}
|
||||||
@@ -153,12 +156,11 @@ getJasmineRequireObj().Spec = function(j$) {
|
|||||||
* @property {String} description - The description passed to the {@link it} that created this spec.
|
* @property {String} description - The description passed to the {@link it} that created this spec.
|
||||||
* @property {String} fullName - The full description including all ancestors of this spec.
|
* @property {String} fullName - The full description including all ancestors of this spec.
|
||||||
* @property {String|null} parentSuiteId - The ID of the suite containing this spec, or null if this spec is not in a describe().
|
* @property {String|null} parentSuiteId - The ID of the suite containing this spec, or null if this spec is not in a describe().
|
||||||
* @property {String} filename - Deprecated. The name of the file the spec was defined in.
|
* @property {String} filename - The name of the file the spec was defined in.
|
||||||
* Note: The value may be incorrect if zone.js is installed or
|
* Note: The value may be incorrect if zone.js is installed or
|
||||||
* `it`/`fit`/`xit` have been replaced with versions that don't maintain the
|
* `it`/`fit`/`xit` have been replaced with versions that don't maintain the
|
||||||
* same call stack height as the originals. This property may be removed in
|
* same call stack height as the originals. You can fix that by setting
|
||||||
* a future version unless there is enough user interest in keeping it.
|
* {@link Configuration#extraItStackFrames}.
|
||||||
* See {@link https://github.com/jasmine/jasmine/issues/2065}.
|
|
||||||
* @property {ExpectationResult[]} failedExpectations - The list of expectations that failed during execution of this spec.
|
* @property {ExpectationResult[]} failedExpectations - The list of expectations that failed during execution of this spec.
|
||||||
* @property {ExpectationResult[]} passedExpectations - The list of expectations that passed during execution of this spec.
|
* @property {ExpectationResult[]} passedExpectations - The list of expectations that passed during execution of this spec.
|
||||||
* @property {ExpectationResult[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec.
|
* @property {ExpectationResult[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec.
|
||||||
@@ -340,7 +342,20 @@ getJasmineRequireObj().Spec = function(j$) {
|
|||||||
* @returns {Array.<string>}
|
* @returns {Array.<string>}
|
||||||
* @since 5.7.0
|
* @since 5.7.0
|
||||||
*/
|
*/
|
||||||
getPath: this.getPath.bind(this)
|
getPath: this.getPath.bind(this),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the file the spec was defined in.
|
||||||
|
* Note: The value may be incorrect if zone.js is installed or
|
||||||
|
* `it`/`fit`/`xit` have been replaced with versions that don't maintain the
|
||||||
|
* same call stack height as the originals. You can fix that by setting
|
||||||
|
* {@link Configuration#extraItStackFrames}.
|
||||||
|
* @name Spec#filename
|
||||||
|
* @readonly
|
||||||
|
* @type {string}
|
||||||
|
* @since 5.13.0
|
||||||
|
*/
|
||||||
|
filename: this.filename
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,48 @@
|
|||||||
getJasmineRequireObj().clearStack = function(j$) {
|
getJasmineRequireObj().StackClearer = function(j$) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const maxInlineCallCount = 10;
|
const maxInlineCallCount = 10;
|
||||||
|
// 25ms gives a good balance of speed and UI responsiveness when running
|
||||||
|
// jasmine-core's own tests in Safari 18. The exact value isn't critical.
|
||||||
|
const safariYieldIntervalMs = 25;
|
||||||
|
|
||||||
function browserQueueMicrotaskImpl(global) {
|
function browserQueueMicrotaskImpl(global) {
|
||||||
const unclampedSetTimeout = getUnclampedSetTimeout(global);
|
const unclampedSetTimeout = getUnclampedSetTimeout(global);
|
||||||
const { queueMicrotask } = global;
|
const { queueMicrotask } = global;
|
||||||
let currentCallCount = 0;
|
let yieldStrategy = 'count';
|
||||||
return function clearStack(fn) {
|
let currentCallCount = 0; // for count strategy
|
||||||
currentCallCount++;
|
let nextSetTimeoutTime; // for time strategy
|
||||||
|
|
||||||
if (currentCallCount < maxInlineCallCount) {
|
return {
|
||||||
queueMicrotask(fn);
|
clearStack(fn) {
|
||||||
} else {
|
currentCallCount++;
|
||||||
currentCallCount = 0;
|
let shouldSetTimeout;
|
||||||
unclampedSetTimeout(fn);
|
|
||||||
|
if (yieldStrategy === 'time') {
|
||||||
|
const now = new Date().getTime();
|
||||||
|
shouldSetTimeout = now >= nextSetTimeoutTime;
|
||||||
|
if (shouldSetTimeout) {
|
||||||
|
nextSetTimeoutTime = now + safariYieldIntervalMs;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
shouldSetTimeout = currentCallCount >= maxInlineCallCount;
|
||||||
|
if (shouldSetTimeout) {
|
||||||
|
currentCallCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldSetTimeout) {
|
||||||
|
unclampedSetTimeout(fn);
|
||||||
|
} else {
|
||||||
|
queueMicrotask(fn);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setSafariYieldStrategy(strategy) {
|
||||||
|
yieldStrategy = strategy;
|
||||||
|
|
||||||
|
if (yieldStrategy === 'time') {
|
||||||
|
nextSetTimeoutTime = new Date().getTime() + safariYieldIntervalMs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -22,8 +50,11 @@ getJasmineRequireObj().clearStack = function(j$) {
|
|||||||
function nodeQueueMicrotaskImpl(global) {
|
function nodeQueueMicrotaskImpl(global) {
|
||||||
const { queueMicrotask } = global;
|
const { queueMicrotask } = global;
|
||||||
|
|
||||||
return function(fn) {
|
return {
|
||||||
queueMicrotask(fn);
|
clearStack(fn) {
|
||||||
|
queueMicrotask(fn);
|
||||||
|
},
|
||||||
|
setSafariYieldStrategy() {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,15 +63,19 @@ getJasmineRequireObj().clearStack = function(j$) {
|
|||||||
const postMessage = getPostMessage(global);
|
const postMessage = getPostMessage(global);
|
||||||
|
|
||||||
let currentCallCount = 0;
|
let currentCallCount = 0;
|
||||||
return function clearStack(fn) {
|
|
||||||
currentCallCount++;
|
|
||||||
|
|
||||||
if (currentCallCount < maxInlineCallCount) {
|
return {
|
||||||
postMessage(fn);
|
clearStack(fn) {
|
||||||
} else {
|
currentCallCount++;
|
||||||
currentCallCount = 0;
|
|
||||||
setTimeout(fn);
|
if (currentCallCount < maxInlineCallCount) {
|
||||||
}
|
postMessage(fn);
|
||||||
|
} else {
|
||||||
|
currentCallCount = 0;
|
||||||
|
setTimeout(fn);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setSafariYieldStrategy() {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +123,7 @@ getJasmineRequireObj().clearStack = function(j$) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getClearStack(global) {
|
function getStackClearer(global) {
|
||||||
const NODE_JS =
|
const NODE_JS =
|
||||||
global.process &&
|
global.process &&
|
||||||
global.process.versions &&
|
global.process.versions &&
|
||||||
@@ -106,12 +141,10 @@ getJasmineRequireObj().clearStack = function(j$) {
|
|||||||
// Unlike browsers, Node doesn't require us to do a periodic setTimeout
|
// Unlike browsers, Node doesn't require us to do a periodic setTimeout
|
||||||
// so we avoid the overhead.
|
// so we avoid the overhead.
|
||||||
return nodeQueueMicrotaskImpl(global);
|
return nodeQueueMicrotaskImpl(global);
|
||||||
} else if (SAFARI_OR_WIN_WEBKIT || !global.MessageChannel /* tests */) {
|
} else if (SAFARI_OR_WIN_WEBKIT) {
|
||||||
// queueMicrotask is dramatically faster than MessageChannel in Safari
|
// queueMicrotask is dramatically faster than MessageChannel in Safari
|
||||||
// and other WebKit-based browsers, such as the one distributed by Playwright
|
// and other WebKit-based browsers, such as the one distributed by Playwright
|
||||||
// to test Safari-like behavior on Windows.
|
// to test Safari-like behavior on Windows.
|
||||||
// Some of our own integration tests provide a mock queueMicrotask in all
|
|
||||||
// environments because it's simpler to mock than MessageChannel.
|
|
||||||
return browserQueueMicrotaskImpl(global);
|
return browserQueueMicrotaskImpl(global);
|
||||||
} else {
|
} else {
|
||||||
// MessageChannel is faster than queueMicrotask in supported browsers
|
// MessageChannel is faster than queueMicrotask in supported browsers
|
||||||
@@ -120,5 +153,5 @@ getJasmineRequireObj().clearStack = function(j$) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return getClearStack;
|
return getStackClearer;
|
||||||
};
|
};
|
||||||
+20
-5
@@ -37,8 +37,11 @@ getJasmineRequireObj().Suite = function(j$) {
|
|||||||
// Key and value will eventually be cloned during reporting. The error
|
// Key and value will eventually be cloned during reporting. The error
|
||||||
// thrown at that point if they aren't cloneable isn't very helpful.
|
// thrown at that point if they aren't cloneable isn't very helpful.
|
||||||
// Throw a better one now.
|
// Throw a better one now.
|
||||||
j$.private.util.assertReporterCloneable(key, 'Key');
|
if (!j$.private.isString(key)) {
|
||||||
|
throw new Error('Key must be a string');
|
||||||
|
}
|
||||||
j$.private.util.assertReporterCloneable(value, 'Value');
|
j$.private.util.assertReporterCloneable(value, 'Value');
|
||||||
|
|
||||||
this.#result.properties = this.#result.properties || {};
|
this.#result.properties = this.#result.properties || {};
|
||||||
this.#result.properties[key] = value;
|
this.#result.properties[key] = value;
|
||||||
}
|
}
|
||||||
@@ -146,12 +149,11 @@ getJasmineRequireObj().Suite = function(j$) {
|
|||||||
* @property {String} description - The description text passed to the {@link describe} that made this suite.
|
* @property {String} description - The description text passed to the {@link describe} that made this suite.
|
||||||
* @property {String} fullName - The full description including all ancestors of this suite.
|
* @property {String} fullName - The full description including all ancestors of this suite.
|
||||||
* @property {String|null} parentSuiteId - The ID of the suite containing this suite, or null if this is not in another describe().
|
* @property {String|null} parentSuiteId - The ID of the suite containing this suite, or null if this is not in another describe().
|
||||||
* @property {String} filename - Deprecated. The name of the file the suite was defined in.
|
* @property {String} filename - The name of the file the suite was defined in.
|
||||||
* Note: The value may be incorrect if zone.js is installed or
|
* Note: The value may be incorrect if zone.js is installed or
|
||||||
* `describe`/`fdescribe`/`xdescribe` have been replaced with versions that
|
* `describe`/`fdescribe`/`xdescribe` have been replaced with versions that
|
||||||
* don't maintain the same call stack height as the originals. This property
|
* don't maintain the same call stack height as the originals. You can fix
|
||||||
* may be removed in a future version unless there is enough user interest
|
* that by setting {@link Configuration#extraDescribeStackFrames}.
|
||||||
* in keeping it. See {@link https://github.com/jasmine/jasmine/issues/2065}.
|
|
||||||
* @property {ExpectationResult[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite.
|
* @property {ExpectationResult[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite.
|
||||||
* @property {ExpectationResult[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite.
|
* @property {ExpectationResult[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite.
|
||||||
* @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite.
|
* @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite.
|
||||||
@@ -359,6 +361,19 @@ getJasmineRequireObj().Suite = function(j$) {
|
|||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
this.description = suite.description;
|
this.description = suite.description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the file the suite was defined in.
|
||||||
|
* Note: The value may be incorrect if zone.js is installed or
|
||||||
|
* `describe`/`fdescribe`/`xdescribe` have been replaced with versions
|
||||||
|
* that don't maintain the same call stack height as the originals. You
|
||||||
|
* can fix that by setting {@link Configuration#extraItStackFrames}.
|
||||||
|
* @name Suite#filename
|
||||||
|
* @readonly
|
||||||
|
* @type {string}
|
||||||
|
* @since 5.13.0
|
||||||
|
*/
|
||||||
|
this.filename = suite.filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -49,7 +49,10 @@ getJasmineRequireObj().TreeRunner = function(j$) {
|
|||||||
_executeSpec(spec, specOverallDone) {
|
_executeSpec(spec, specOverallDone) {
|
||||||
const onStart = next => {
|
const onStart = next => {
|
||||||
this.#currentRunableTracker.setCurrentSpec(spec);
|
this.#currentRunableTracker.setCurrentSpec(spec);
|
||||||
this.#runableResources.initForRunable(spec.id, spec.parentSuiteId);
|
this.#runableResources.initForRunable(
|
||||||
|
spec.id,
|
||||||
|
spec.parentSuiteId || this.#executionTree.topSuite.id
|
||||||
|
);
|
||||||
this.#reportDispatcher.specStarted(spec.startedEvent()).then(next);
|
this.#reportDispatcher.specStarted(spec.startedEvent()).then(next);
|
||||||
};
|
};
|
||||||
const resultCallback = (result, next) => {
|
const resultCallback = (result, next) => {
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
getJasmineRequireObj().AllOf = function(j$) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function AllOf() {
|
||||||
|
const expectedValues = Array.from(arguments);
|
||||||
|
if (expectedValues.length === 0) {
|
||||||
|
throw new TypeError(
|
||||||
|
'jasmine.allOf() expects at least one argument to be passed.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.expectedValues = expectedValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
AllOf.prototype.asymmetricMatch = function(other, matchersUtil) {
|
||||||
|
for (const expectedValue of this.expectedValues) {
|
||||||
|
if (!matchersUtil.equals(other, expectedValue)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
AllOf.prototype.jasmineToString = function(pp) {
|
||||||
|
return '<jasmine.allOf(' + pp(this.expectedValues) + ')>';
|
||||||
|
};
|
||||||
|
|
||||||
|
return AllOf;
|
||||||
|
};
|
||||||
@@ -229,6 +229,19 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||||
|
* value being compared matches every provided equality tester.
|
||||||
|
* @name asymmetricEqualityTesters.allOf
|
||||||
|
* @emittedName jasmine.allOf
|
||||||
|
* @since 5.13.0
|
||||||
|
* @function
|
||||||
|
* @param {...*} arguments - The asymmetric equality checkers to compare.
|
||||||
|
*/
|
||||||
|
j$.allOf = function() {
|
||||||
|
return new j$.AllOf(...arguments);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||||
* value being compared is an instance of the specified class/constructor.
|
* value being compared is an instance of the specified class/constructor.
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ getJasmineRequireObj().reporterEvents = function(j$) {
|
|||||||
* {@link ReporterCapabilities} will apply.
|
* {@link ReporterCapabilities} will apply.
|
||||||
* @name Reporter#reporterCapabilities
|
* @name Reporter#reporterCapabilities
|
||||||
* @type ReporterCapabilities | undefined
|
* @type ReporterCapabilities | undefined
|
||||||
|
* @optional
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
@@ -73,6 +74,7 @@ getJasmineRequireObj().reporterEvents = function(j$) {
|
|||||||
/**
|
/**
|
||||||
* `specStarted` is invoked when an `it` starts to run (including associated `beforeEach` functions)
|
* `specStarted` is invoked when an `it` starts to run (including associated `beforeEach` functions)
|
||||||
* @function
|
* @function
|
||||||
|
* @optional
|
||||||
* @name Reporter#specStarted
|
* @name Reporter#specStarted
|
||||||
* @param {SpecStartedEvent} result Information about the individual {@link it} being run
|
* @param {SpecStartedEvent} result Information about the individual {@link it} being run
|
||||||
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
||||||
|
|||||||
@@ -26,11 +26,12 @@ var getJasmineRequireObj = (function() {
|
|||||||
j$.private.util = jRequire.util(j$);
|
j$.private.util = jRequire.util(j$);
|
||||||
j$.private.errors = jRequire.errors();
|
j$.private.errors = jRequire.errors();
|
||||||
j$.private.formatErrorMsg = jRequire.formatErrorMsg(j$);
|
j$.private.formatErrorMsg = jRequire.formatErrorMsg(j$);
|
||||||
|
j$.private.AllOf = jRequire.AllOf(j$);
|
||||||
j$.private.Any = jRequire.Any(j$);
|
j$.private.Any = jRequire.Any(j$);
|
||||||
j$.private.Anything = jRequire.Anything(j$);
|
j$.private.Anything = jRequire.Anything(j$);
|
||||||
j$.private.CallTracker = jRequire.CallTracker(j$);
|
j$.private.CallTracker = jRequire.CallTracker(j$);
|
||||||
j$.private.MockDate = jRequire.MockDate(j$);
|
j$.private.MockDate = jRequire.MockDate(j$);
|
||||||
j$.private.getClearStack = jRequire.clearStack(j$);
|
j$.private.getStackClearer = jRequire.StackClearer(j$);
|
||||||
j$.private.Clock = jRequire.Clock();
|
j$.private.Clock = jRequire.Clock();
|
||||||
j$.private.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$);
|
j$.private.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$);
|
||||||
j$.private.Deprecator = jRequire.Deprecator(j$);
|
j$.private.Deprecator = jRequire.Deprecator(j$);
|
||||||
|
|||||||
+15
-8
@@ -24,6 +24,7 @@ jasmineRequire.AlertsView = function(j$) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove this once HtmlReporterV2 doesn't use it
|
||||||
addFailureToggle(onClickFailures, onClickSpecList) {
|
addFailureToggle(onClickFailures, onClickSpecList) {
|
||||||
const failuresLink = createDom(
|
const failuresLink = createDom(
|
||||||
'a',
|
'a',
|
||||||
@@ -46,14 +47,20 @@ jasmineRequire.AlertsView = function(j$) {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.#createAndAdd('jasmine-menu jasmine-bar jasmine-spec-list', [
|
this.rootEl.appendChild(
|
||||||
createDom('span', {}, 'Spec List | '),
|
createDom(
|
||||||
failuresLink
|
'span',
|
||||||
]);
|
{ className: 'jasmine-menu jasmine-bar jasmine-spec-list' },
|
||||||
this.#createAndAdd('jasmine-menu jasmine-bar jasmine-failure-list', [
|
[createDom('span', {}, 'Spec List | '), failuresLink]
|
||||||
specListLink,
|
)
|
||||||
createDom('span', {}, ' | Failures ')
|
);
|
||||||
]);
|
this.rootEl.appendChild(
|
||||||
|
createDom(
|
||||||
|
'span',
|
||||||
|
{ className: 'jasmine-menu jasmine-bar jasmine-failure-list' },
|
||||||
|
[specListLink, createDom('span', {}, ' | Failures ')]
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
addGlobalFailure(failure) {
|
addGlobalFailure(failure) {
|
||||||
|
|||||||
@@ -142,16 +142,52 @@ jasmineRequire.HtmlReporter = function(j$) {
|
|||||||
results.appendChild(summary.rootEl);
|
results.appendChild(summary.rootEl);
|
||||||
|
|
||||||
if (this.#stateBuilder.anyNonTopSuiteFailures) {
|
if (this.#stateBuilder.anyNonTopSuiteFailures) {
|
||||||
this.#alerts.addFailureToggle(
|
this.#addFailureToggle();
|
||||||
() => this.#setMenuModeTo('jasmine-failure-list'),
|
|
||||||
() => this.#setMenuModeTo('jasmine-spec-list')
|
|
||||||
);
|
|
||||||
|
|
||||||
this.#setMenuModeTo('jasmine-failure-list');
|
this.#setMenuModeTo('jasmine-failure-list');
|
||||||
this.#failures.show();
|
this.#failures.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#addFailureToggle() {
|
||||||
|
const onClickFailures = () => this.#setMenuModeTo('jasmine-failure-list');
|
||||||
|
const onClickSpecList = () => this.#setMenuModeTo('jasmine-spec-list');
|
||||||
|
const failuresLink = createDom(
|
||||||
|
'a',
|
||||||
|
{ className: 'jasmine-failures-menu', href: '#' },
|
||||||
|
'Failures'
|
||||||
|
);
|
||||||
|
let specListLink = createDom(
|
||||||
|
'a',
|
||||||
|
{ className: 'jasmine-spec-list-menu', href: '#' },
|
||||||
|
'Spec List'
|
||||||
|
);
|
||||||
|
|
||||||
|
failuresLink.onclick = function() {
|
||||||
|
onClickFailures();
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
specListLink.onclick = function() {
|
||||||
|
onClickSpecList();
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.#alerts.addBar(
|
||||||
|
createDom(
|
||||||
|
'span',
|
||||||
|
{ className: 'jasmine-menu jasmine-bar jasmine-spec-list' },
|
||||||
|
[createDom('span', {}, 'Spec List | '), failuresLink]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
this.#alerts.addBar(
|
||||||
|
createDom(
|
||||||
|
'span',
|
||||||
|
{ className: 'jasmine-menu jasmine-bar jasmine-failure-list' },
|
||||||
|
[specListLink, createDom('span', {}, ' | Failures ')]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#find(selector) {
|
#find(selector) {
|
||||||
return this.#getContainer().querySelector(
|
return this.#getContainer().querySelector(
|
||||||
'.jasmine_html-reporter ' + selector
|
'.jasmine_html-reporter ' + selector
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
|
|||||||
|
|
||||||
const { createDom, noExpectations } = j$.private.htmlReporterUtils;
|
const { createDom, noExpectations } = j$.private.htmlReporterUtils;
|
||||||
|
|
||||||
|
const specListTabId = 'jasmine-specListTab';
|
||||||
|
const failuresTabId = 'jasmine-failuresTab';
|
||||||
|
const perfTabId = 'jasmine-perfTab';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class HtmlReporterV2
|
* @class HtmlReporterV2
|
||||||
* @classdesc Displays results and allows re-running individual specs and suites.
|
* @classdesc Displays results and allows re-running individual specs and suites.
|
||||||
@@ -15,7 +19,7 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
|
|||||||
* const reporter = new jasmine.HtmlReporterV2({
|
* const reporter = new jasmine.HtmlReporterV2({
|
||||||
* env,
|
* env,
|
||||||
* urls,
|
* urls,
|
||||||
* container: document.body
|
* getContainer: () => document.body
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
class HtmlReporterV2 {
|
class HtmlReporterV2 {
|
||||||
@@ -31,6 +35,7 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
|
|||||||
// Sub-views
|
// Sub-views
|
||||||
#alerts;
|
#alerts;
|
||||||
#statusBar;
|
#statusBar;
|
||||||
|
#tabBar;
|
||||||
#progress;
|
#progress;
|
||||||
#banner;
|
#banner;
|
||||||
#failures;
|
#failures;
|
||||||
@@ -68,6 +73,25 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
|
|||||||
this.#statusBar = new j$.private.OverallStatusBar(this.#urlBuilder);
|
this.#statusBar = new j$.private.OverallStatusBar(this.#urlBuilder);
|
||||||
this.#statusBar.showRunning();
|
this.#statusBar.showRunning();
|
||||||
this.#alerts.addBar(this.#statusBar.rootEl);
|
this.#alerts.addBar(this.#statusBar.rootEl);
|
||||||
|
|
||||||
|
this.#tabBar = new j$.private.TabBar(
|
||||||
|
[
|
||||||
|
{ id: specListTabId, label: 'Spec List' },
|
||||||
|
{ id: failuresTabId, label: 'Failures' },
|
||||||
|
{ id: perfTabId, label: 'Performance' }
|
||||||
|
],
|
||||||
|
tabId => {
|
||||||
|
if (tabId === specListTabId) {
|
||||||
|
this.#setMenuModeTo('jasmine-spec-list');
|
||||||
|
} else if (tabId === failuresTabId) {
|
||||||
|
this.#setMenuModeTo('jasmine-failure-list');
|
||||||
|
} else {
|
||||||
|
this.#setMenuModeTo('jasmine-performance');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.#alerts.addBar(this.#tabBar.rootEl);
|
||||||
|
|
||||||
this.#progress = new ProgressView();
|
this.#progress = new ProgressView();
|
||||||
this.#banner = new j$.private.Banner(
|
this.#banner = new j$.private.Banner(
|
||||||
this.#queryString.navigateWithNewParam.bind(this.#queryString),
|
this.#queryString.navigateWithNewParam.bind(this.#queryString),
|
||||||
@@ -158,15 +182,17 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
|
|||||||
);
|
);
|
||||||
summary.addResults(this.#stateBuilder.topResults);
|
summary.addResults(this.#stateBuilder.topResults);
|
||||||
results.appendChild(summary.rootEl);
|
results.appendChild(summary.rootEl);
|
||||||
|
const perf = new j$.private.PerformanceView();
|
||||||
|
perf.addResults(this.#stateBuilder.topResults);
|
||||||
|
results.appendChild(perf.rootEl);
|
||||||
|
this.#tabBar.showTab(specListTabId);
|
||||||
|
this.#tabBar.showTab(perfTabId);
|
||||||
|
|
||||||
if (this.#stateBuilder.anyNonTopSuiteFailures) {
|
if (this.#stateBuilder.anyNonTopSuiteFailures) {
|
||||||
this.#alerts.addFailureToggle(
|
this.#tabBar.showTab(failuresTabId);
|
||||||
() => this.#setMenuModeTo('jasmine-failure-list'),
|
this.#tabBar.selectTab(failuresTabId);
|
||||||
() => this.#setMenuModeTo('jasmine-spec-list')
|
} else {
|
||||||
);
|
this.#tabBar.selectTab(specListTabId);
|
||||||
|
|
||||||
this.#setMenuModeTo('jasmine-failure-list');
|
|
||||||
this.#failures.show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,7 +231,6 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
|
|||||||
this.rootEl.value = this.rootEl.value + 1;
|
this.rootEl.value = this.rootEl.value + 1;
|
||||||
|
|
||||||
if (result.status === 'failed') {
|
if (result.status === 'failed') {
|
||||||
// TODO: also a non-color indicator
|
|
||||||
this.rootEl.classList.add('failed');
|
this.rootEl.classList.add('failed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,10 @@ jasmineRequire.HtmlReporterV2Urls = function(j$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link Configuration} from the current page's URL.
|
* Creates a {@link Configuration} from the current page's URL. Supported
|
||||||
|
* query string parameters include all those set by {@link HtmlReporterV2}
|
||||||
|
* as well as spec=partialPath, which filters out specs whose paths don't
|
||||||
|
* contain partialPath.
|
||||||
* @returns {Configuration}
|
* @returns {Configuration}
|
||||||
* @example
|
* @example
|
||||||
* const urls = new jasmine.HtmlReporterV2Urls();
|
* const urls = new jasmine.HtmlReporterV2Urls();
|
||||||
@@ -47,9 +50,10 @@ jasmineRequire.HtmlReporterV2Urls = function(j$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const specFilter = new j$.private.HtmlSpecFilterV2({
|
const specFilter = new j$.private.HtmlSpecFilterV2({
|
||||||
filterString: () => {
|
filterParams: () => ({
|
||||||
return this.queryString.getParam('path');
|
path: this.queryString.getParam('path'),
|
||||||
}
|
spec: this.queryString.getParam('spec')
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
config.specFilter = function(spec) {
|
config.specFilter = function(spec) {
|
||||||
|
|||||||
@@ -1,34 +1,34 @@
|
|||||||
jasmineRequire.HtmlSpecFilterV2 = function() {
|
jasmineRequire.HtmlSpecFilterV2 = function() {
|
||||||
class HtmlSpecFilterV2 {
|
class HtmlSpecFilterV2 {
|
||||||
#getFilterString;
|
#getFilterParams;
|
||||||
|
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
this.#getFilterString = options.filterString;
|
this.#getFilterParams = options.filterParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines whether the spec with the specified name should be executed.
|
|
||||||
* @name HtmlSpecFilterV2#matches
|
|
||||||
* @function
|
|
||||||
* @param {Spec} spec
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
matches(spec) {
|
matches(spec) {
|
||||||
const filterString = this.#getFilterString();
|
const params = this.#getFilterParams();
|
||||||
|
|
||||||
if (!filterString) {
|
if (params.path) {
|
||||||
return true;
|
return this.#matchesPath(spec, JSON.parse(params.path));
|
||||||
|
} else if (params.spec) {
|
||||||
|
// Like legacy HtmlSpecFilter, retained because it's convenient for
|
||||||
|
// hand-constructing filter URLs
|
||||||
|
return spec.getFullName().includes(params.spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterPath = JSON.parse(this.#getFilterString());
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#matchesPath(spec, path) {
|
||||||
const specPath = spec.getPath();
|
const specPath = spec.getPath();
|
||||||
|
|
||||||
if (filterPath.length > specPath.length) {
|
if (path.length > specPath.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < filterPath.length; i++) {
|
for (let i = 0; i < path.length; i++) {
|
||||||
if (specPath[i] !== filterPath[i]) {
|
if (specPath[i] !== path[i]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
jasmineRequire.PerformanceView = function(j$) {
|
||||||
|
const createDom = j$.private.htmlReporterUtils.createDom;
|
||||||
|
const MAX_SLOW_SPECS = 20;
|
||||||
|
|
||||||
|
class PerformanceView {
|
||||||
|
#summary;
|
||||||
|
#tbody;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.#tbody = document.createElement('tbody');
|
||||||
|
this.#summary = document.createElement('div');
|
||||||
|
this.rootEl = createDom(
|
||||||
|
'div',
|
||||||
|
{ className: 'jasmine-performance-view' },
|
||||||
|
createDom('h2', {}, 'Performance'),
|
||||||
|
this.#summary,
|
||||||
|
createDom('h3', {}, 'Slowest Specs'),
|
||||||
|
createDom(
|
||||||
|
'table',
|
||||||
|
{},
|
||||||
|
createDom(
|
||||||
|
'thead',
|
||||||
|
{},
|
||||||
|
createDom(
|
||||||
|
'tr',
|
||||||
|
{},
|
||||||
|
createDom('th', {}, 'Duration'),
|
||||||
|
createDom('th', {}, 'Spec Name')
|
||||||
|
)
|
||||||
|
),
|
||||||
|
this.#tbody
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
addResults(resultsTree) {
|
||||||
|
const specResults = [];
|
||||||
|
getSpecResults(resultsTree, specResults);
|
||||||
|
|
||||||
|
if (specResults.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
specResults.sort(function(a, b) {
|
||||||
|
if (a.duration < b.duration) {
|
||||||
|
return 1;
|
||||||
|
} else if (a.duration > b.duration) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.#populateSumary(specResults);
|
||||||
|
this.#populateTable(specResults);
|
||||||
|
}
|
||||||
|
|
||||||
|
#populateSumary(specResults) {
|
||||||
|
const total = specResults.map(r => r.duration).reduce((a, b) => a + b, 0);
|
||||||
|
const mean = total / specResults.length;
|
||||||
|
const median = specResults[Math.floor(specResults.length / 2)].duration;
|
||||||
|
this.#summary.appendChild(
|
||||||
|
document.createTextNode(`Mean spec run time: ${mean.toFixed(0)}ms`)
|
||||||
|
);
|
||||||
|
this.#summary.appendChild(document.createElement('br'));
|
||||||
|
this.#summary.appendChild(
|
||||||
|
document.createTextNode(`Median spec run time: ${median}ms`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#populateTable(specResults) {
|
||||||
|
specResults = specResults.slice(0, MAX_SLOW_SPECS);
|
||||||
|
|
||||||
|
for (const r of specResults) {
|
||||||
|
this.#tbody.appendChild(
|
||||||
|
createDom(
|
||||||
|
'tr',
|
||||||
|
{},
|
||||||
|
createDom('td', {}, `${r.duration}ms`),
|
||||||
|
createDom('td', {}, r.fullName)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSpecResults(resultsTree, dest) {
|
||||||
|
for (const node of resultsTree.children) {
|
||||||
|
if (node.type === 'suite') {
|
||||||
|
getSpecResults(node, dest);
|
||||||
|
} else if (node.result.status !== 'excluded') {
|
||||||
|
dest.push(node.result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PerformanceView;
|
||||||
|
};
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
jasmineRequire.TabBar = function(j$) {
|
||||||
|
const createDom = j$.private.htmlReporterUtils.createDom;
|
||||||
|
|
||||||
|
class TabBar {
|
||||||
|
#tabs;
|
||||||
|
#onSelectTab;
|
||||||
|
|
||||||
|
// tabSpecs should be an array of {id, label}.
|
||||||
|
// All tabs are initially not visible and not selected.
|
||||||
|
constructor(tabSpecs, onSelectTab) {
|
||||||
|
this.#onSelectTab = onSelectTab;
|
||||||
|
this.#tabs = [];
|
||||||
|
this.#tabs = tabSpecs.map(ts => new Tab(ts, () => this.selectTab(ts.id)));
|
||||||
|
|
||||||
|
this.rootEl = createDom(
|
||||||
|
'span',
|
||||||
|
{ className: 'jasmine-menu jasmine-bar' },
|
||||||
|
this.#tabs.map(t => t.rootEl)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
showTab(id) {
|
||||||
|
for (const tab of this.#tabs) {
|
||||||
|
if (tab.rootEl.id === id) {
|
||||||
|
tab.setVisibility(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selectTab(id) {
|
||||||
|
for (const tab of this.#tabs) {
|
||||||
|
tab.setSelected(tab.rootEl.id === id);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#onSelectTab(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Tab {
|
||||||
|
#spec;
|
||||||
|
#onClick;
|
||||||
|
|
||||||
|
constructor(spec, onClick) {
|
||||||
|
this.#spec = spec;
|
||||||
|
this.#onClick = onClick;
|
||||||
|
this.rootEl = createDom(
|
||||||
|
'span',
|
||||||
|
{ id: spec.id, className: 'jasmine-tab jasmine-hidden' },
|
||||||
|
this.#createLink()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
setVisibility(visible) {
|
||||||
|
this.rootEl.classList.toggle('jasmine-hidden', !visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
setSelected(selected) {
|
||||||
|
if (selected) {
|
||||||
|
this.rootEl.textContent = this.#spec.label;
|
||||||
|
} else {
|
||||||
|
this.rootEl.textContent = '';
|
||||||
|
this.rootEl.appendChild(this.#createLink());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#createLink() {
|
||||||
|
const link = createDom('a', { href: '#' }, this.#spec.label);
|
||||||
|
link.addEventListener('click', e => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.#onClick();
|
||||||
|
});
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TabBar;
|
||||||
|
};
|
||||||
@@ -23,7 +23,7 @@ $failing-mark: "\d7";
|
|||||||
$pending-mark: "*";
|
$pending-mark: "*";
|
||||||
$space: "\0020";
|
$space: "\0020";
|
||||||
|
|
||||||
$font-size: 11px;
|
$font-size: 12px;
|
||||||
$large-font-size: 14px;
|
$large-font-size: 14px;
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@@ -280,15 +280,25 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// simplify toggle control between the two menu bars
|
// simplify toggle control between the two menu bars
|
||||||
|
// TODO: clean this up once HtmlReporter is removed
|
||||||
&.jasmine-spec-list {
|
&.jasmine-spec-list {
|
||||||
.jasmine-bar.jasmine-menu.jasmine-failure-list,
|
.jasmine-bar.jasmine-menu.jasmine-failure-list,
|
||||||
.jasmine-results .jasmine-failures {
|
.jasmine-results .jasmine-failures,
|
||||||
|
.jasmine-performance-view {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.jasmine-failure-list {
|
&.jasmine-failure-list {
|
||||||
.jasmine-bar.jasmine-menu.jasmine-spec-list,
|
.jasmine-bar.jasmine-menu.jasmine-spec-list,
|
||||||
|
.jasmine-summary,
|
||||||
|
.jasmine-performance-view {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.jasmine-performance {
|
||||||
|
.jasmine-results .jasmine-failures,
|
||||||
.jasmine-summary {
|
.jasmine-summary {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@@ -464,3 +474,26 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.jasmine-hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jasmine-tab + .jasmine-tab:before {
|
||||||
|
content: ' | ';
|
||||||
|
}
|
||||||
|
|
||||||
|
.jasmine-performance-view {
|
||||||
|
h2, h3 {
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-spacing: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ jasmineRequire.html = function(j$) {
|
|||||||
j$.private.SymbolsView = jasmineRequire.SymbolsView(j$);
|
j$.private.SymbolsView = jasmineRequire.SymbolsView(j$);
|
||||||
j$.private.SummaryTreeView = jasmineRequire.SummaryTreeView(j$);
|
j$.private.SummaryTreeView = jasmineRequire.SummaryTreeView(j$);
|
||||||
j$.private.FailuresView = jasmineRequire.FailuresView(j$);
|
j$.private.FailuresView = jasmineRequire.FailuresView(j$);
|
||||||
|
j$.private.PerformanceView = jasmineRequire.PerformanceView(j$);
|
||||||
|
j$.private.TabBar = jasmineRequire.TabBar(j$);
|
||||||
j$.HtmlReporter = jasmineRequire.HtmlReporter(j$);
|
j$.HtmlReporter = jasmineRequire.HtmlReporter(j$);
|
||||||
j$.HtmlReporterV2Urls = jasmineRequire.HtmlReporterV2Urls(j$);
|
j$.HtmlReporterV2Urls = jasmineRequire.HtmlReporterV2Urls(j$);
|
||||||
j$.HtmlReporterV2 = jasmineRequire.HtmlReporterV2(j$);
|
j$.HtmlReporterV2 = jasmineRequire.HtmlReporterV2(j$);
|
||||||
|
|||||||
Reference in New Issue
Block a user