jasmine-core
Advanced tools
@@ -61,2 +61,8 @@ /* | ||
| 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()); | ||
@@ -63,0 +69,0 @@ |
@@ -38,2 +38,4 @@ /* | ||
| j$.private.FailuresView = jasmineRequire.FailuresView(j$); | ||
| j$.private.PerformanceView = jasmineRequire.PerformanceView(j$); | ||
| j$.private.TabBar = jasmineRequire.TabBar(j$); | ||
| j$.HtmlReporter = jasmineRequire.HtmlReporter(j$); | ||
@@ -191,7 +193,3 @@ j$.HtmlReporterV2Urls = jasmineRequire.HtmlReporterV2Urls(j$); | ||
| if (this.#stateBuilder.anyNonTopSuiteFailures) { | ||
| this.#alerts.addFailureToggle( | ||
| () => this.#setMenuModeTo('jasmine-failure-list'), | ||
| () => this.#setMenuModeTo('jasmine-spec-list') | ||
| ); | ||
| this.#addFailureToggle(); | ||
| this.#setMenuModeTo('jasmine-failure-list'); | ||
@@ -202,2 +200,42 @@ 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) { | ||
@@ -440,2 +478,3 @@ return this.#getContainer().querySelector( | ||
| // TODO: remove this once HtmlReporterV2 doesn't use it | ||
| addFailureToggle(onClickFailures, onClickSpecList) { | ||
@@ -463,10 +502,16 @@ const failuresLink = createDom( | ||
| this.#createAndAdd('jasmine-menu jasmine-bar jasmine-spec-list', [ | ||
| createDom('span', {}, 'Spec List | '), | ||
| failuresLink | ||
| ]); | ||
| this.#createAndAdd('jasmine-menu jasmine-bar jasmine-failure-list', [ | ||
| specListLink, | ||
| createDom('span', {}, ' | Failures ') | ||
| ]); | ||
| this.rootEl.appendChild( | ||
| createDom( | ||
| 'span', | ||
| { className: 'jasmine-menu jasmine-bar jasmine-spec-list' }, | ||
| [createDom('span', {}, 'Spec List | '), failuresLink] | ||
| ) | ||
| ); | ||
| this.rootEl.appendChild( | ||
| createDom( | ||
| 'span', | ||
| { className: 'jasmine-menu jasmine-bar jasmine-failure-list' }, | ||
| [specListLink, createDom('span', {}, ' | Failures ')] | ||
| ) | ||
| ); | ||
| } | ||
@@ -954,2 +999,6 @@ | ||
| const specListTabId = 'jasmine-specListTab'; | ||
| const failuresTabId = 'jasmine-failuresTab'; | ||
| const perfTabId = 'jasmine-perfTab'; | ||
| /** | ||
@@ -967,3 +1016,3 @@ * @class HtmlReporterV2 | ||
| * urls, | ||
| * container: document.body | ||
| * getContainer: () => document.body | ||
| * }); | ||
@@ -984,2 +1033,3 @@ */ | ||
| #statusBar; | ||
| #tabBar; | ||
| #progress; | ||
@@ -1022,2 +1072,21 @@ #banner; | ||
| 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(); | ||
@@ -1113,11 +1182,13 @@ this.#banner = new j$.private.Banner( | ||
| 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) { | ||
| this.#alerts.addFailureToggle( | ||
| () => this.#setMenuModeTo('jasmine-failure-list'), | ||
| () => this.#setMenuModeTo('jasmine-spec-list') | ||
| ); | ||
| this.#setMenuModeTo('jasmine-failure-list'); | ||
| this.#failures.show(); | ||
| this.#tabBar.showTab(failuresTabId); | ||
| this.#tabBar.selectTab(failuresTabId); | ||
| } else { | ||
| this.#tabBar.selectTab(specListTabId); | ||
| } | ||
@@ -1161,3 +1232,2 @@ } | ||
| if (result.status === 'failed') { | ||
| // TODO: also a non-color indicator | ||
| this.rootEl.classList.add('failed'); | ||
@@ -1247,3 +1317,6 @@ } | ||
| /** | ||
| * 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} | ||
@@ -1274,5 +1347,6 @@ * @example | ||
| const specFilter = new j$.private.HtmlSpecFilterV2({ | ||
| filterString: () => { | ||
| return this.queryString.getParam('path'); | ||
| } | ||
| filterParams: () => ({ | ||
| path: this.queryString.getParam('path'), | ||
| spec: this.queryString.getParam('spec') | ||
| }) | ||
| }); | ||
@@ -1297,31 +1371,31 @@ | ||
| class HtmlSpecFilterV2 { | ||
| #getFilterString; | ||
| #getFilterParams; | ||
| 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) { | ||
| const filterString = this.#getFilterString(); | ||
| const params = this.#getFilterParams(); | ||
| if (!filterString) { | ||
| return true; | ||
| if (params.path) { | ||
| 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(); | ||
| if (filterPath.length > specPath.length) { | ||
| if (path.length > specPath.length) { | ||
| return false; | ||
| } | ||
| for (let i = 0; i < filterPath.length; i++) { | ||
| if (specPath[i] !== filterPath[i]) { | ||
| for (let i = 0; i < path.length; i++) { | ||
| if (specPath[i] !== path[i]) { | ||
| return false; | ||
@@ -1447,2 +1521,101 @@ } | ||
| 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$) { | ||
@@ -1679,1 +1852,79 @@ 'use strict'; | ||
| }; | ||
| 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; | ||
| }; |
@@ -11,3 +11,3 @@ @charset "UTF-8"; | ||
| margin: -8px; | ||
| font-size: 11px; | ||
| font-size: 12px; | ||
| font-family: Monaco, "Lucida Console", monospace; | ||
@@ -67,3 +67,3 @@ line-height: 14px; | ||
| padding-right: 9px; | ||
| font-size: 11px; | ||
| font-size: 12px; | ||
| } | ||
@@ -203,9 +203,15 @@ .jasmine_html-reporter .jasmine-symbol-summary { | ||
| .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; | ||
| } | ||
| .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; | ||
| } | ||
| .jasmine_html-reporter .jasmine-results { | ||
@@ -329,2 +335,21 @@ margin-top: 14px; | ||
| 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; | ||
| } |
+1
-1
| { | ||
| "name": "jasmine-core", | ||
| "license": "MIT", | ||
| "version": "6.0.0-alpha.1", | ||
| "version": "6.0.0-alpha.2", | ||
| "repository": { | ||
@@ -6,0 +6,0 @@ "type": "git", |
+1
-1
@@ -33,3 +33,3 @@ <a name="README"><img src="https://raw.githubusercontent.com/jasmine/jasmine/main/images/jasmine-horizontal.svg" width="400px" alt="Jasmine"></a> | ||
| | Node | 20, 22, 24 | | ||
| | Safari | 16*, 17* | | ||
| | Safari | 16*, 17*, 26* | | ||
| | Chrome | Evergreen | | ||
@@ -36,0 +36,0 @@ | Firefox | Evergreen, 102*, 115*, 128*, 140 | |
Sorry, the diff of this file is too big to display
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
456750
3.03%13084
3.21%87
6.1%