Merge branch '3.99' into 4.0

This commit is contained in:
Steve Gravrock
2021-07-10 09:13:28 -07:00
36 changed files with 1043 additions and 277 deletions

View File

@@ -96,8 +96,8 @@ describe('AsyncExpectation', function() {
jasmine.getEnv().requirePromises();
var matchersUtil = {
buildFailureMessage: function() {
return 'failure message';
pp: function(val) {
return val.toString();
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
@@ -114,7 +114,8 @@ describe('AsyncExpectation', function() {
expect(addExpectationResult).toHaveBeenCalledWith(
false,
jasmine.objectContaining({
message: 'Some context: failure message'
message:
'Some context: Expected a promise to be resolved but it was rejected with rejected.'
})
);
});
@@ -144,7 +145,8 @@ describe('AsyncExpectation', function() {
false,
jasmine.objectContaining({
message:
"Some context: Expected a promise to be resolved to 'a' but it was rejected."
"Some context: Expected a promise to be resolved to 'a' " +
"but it was rejected with 'b'."
})
);
});

View File

@@ -407,6 +407,123 @@ describe('SpyRegistry', function() {
expect(subject.toString).not.toBe('I am a spy');
expect(subject.hasOwnProperty).not.toBe('I am a spy');
});
describe('when includeNonEnumerable is true', function() {
it('does not override Object.prototype methods', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: function() {
return 'I am a spy';
}
});
var subject = {
spied1: function() {}
};
spyRegistry.spyOnAllFunctions(subject, true);
expect(subject.spied1).toBe('I am a spy');
expect(subject.toString).not.toBe('I am a spy');
expect(subject.hasOwnProperty).not.toBe('I am a spy');
});
it('overrides non-enumerable properties', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: function() {
return 'I am a spy';
}
});
var subject = {
spied1: function() {},
spied2: function() {}
};
Object.defineProperty(subject, 'spied2', {
enumerable: false,
writable: true,
configurable: true
});
spyRegistry.spyOnAllFunctions(subject, true);
expect(subject.spied1).toBe('I am a spy');
expect(subject.spied2).toBe('I am a spy');
});
it('should not spy on non-enumerable functions named constructor', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: function() {
return 'I am a spy';
}
});
var subject = {
constructor: function() {}
};
Object.defineProperty(subject, 'constructor', {
enumerable: false,
writable: true,
configurable: true
});
spyRegistry.spyOnAllFunctions(subject, true);
expect(subject.constructor).not.toBe('I am a spy');
});
it('should spy on enumerable functions named constructor', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: function() {
return 'I am a spy';
}
});
var subject = {
constructor: function() {}
};
spyRegistry.spyOnAllFunctions(subject, true);
expect(subject.constructor).toBe('I am a spy');
});
it('should not throw an exception if we try and access strict mode restricted properties', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: function() {
return 'I am a spy';
}
});
var subject = function() {};
var fn = function() {
spyRegistry.spyOnAllFunctions(subject, true);
};
expect(fn).not.toThrow();
});
it('should not spy on properties which are more permissable further up the prototype chain', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: function() {
return 'I am a spy';
}
});
var subjectParent = Object.defineProperty({}, 'sharedProp', {
value: function() {},
writable: true,
configurable: true
});
var subject = Object.create(subjectParent);
Object.defineProperty(subject, 'sharedProp', {
value: function() {}
});
var fn = function() {
spyRegistry.spyOnAllFunctions(subject, true);
};
expect(fn).not.toThrow();
expect(subject).not.toBe('I am a spy');
});
});
});
describe('#clearSpies', function() {

View File

@@ -213,7 +213,7 @@ describe('Spies', function() {
).toBe(1);
});
it('allows base name to be ommitted when assigning methods and properties', function() {
it('allows base name to be omitted when assigning methods and properties', function() {
var spyObj = env.createSpyObj({ m: 3 }, { p: 4 });
expect(spyObj.m()).toEqual(3);

View File

@@ -74,4 +74,33 @@ describe('base helpers', function() {
expect(jasmineUnderTest.isURL({})).toBe(false);
});
});
describe('isPending_', function() {
it('returns a promise that resolves to true when the promise is pending', function() {
jasmine.getEnv().requirePromises();
// eslint-disable-next-line compat/compat
var promise = new Promise(function() {});
return expectAsync(jasmineUnderTest.isPending_(promise)).toBeResolvedTo(
true
);
});
it('returns a promise that resolves to false when the promise is resolved', function() {
jasmine.getEnv().requirePromises();
// eslint-disable-next-line compat/compat
var promise = Promise.resolve();
return expectAsync(jasmineUnderTest.isPending_(promise)).toBeResolvedTo(
false
);
});
it('returns a promise that resolves to false when the promise is rejected', function() {
jasmine.getEnv().requirePromises();
// eslint-disable-next-line compat/compat
var promise = Promise.reject();
return expectAsync(jasmineUnderTest.isPending_(promise)).toBeResolvedTo(
false
);
});
});
});

View File

@@ -754,4 +754,89 @@ describe('Matchers (Integration)', function() {
'a predicate, but it threw Error with message |nope|.'
});
});
describe('When an async matcher is used with .already()', function() {
it('propagates the matcher result when the promise is resolved', function(done) {
jasmine.getEnv().requirePromises();
env.it('a spec', function() {
// eslint-disable-next-line compat/compat
return env.expectAsync(Promise.resolve()).already.toBeRejected();
});
var specExpectations = function(result) {
expect(result.status).toEqual('failed');
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(1);
expect(result.failedExpectations[0].message).toEqual(
'Expected [object Promise] to be rejected.'
);
expect(result.failedExpectations[0].matcherName)
.withContext('Matcher name')
.not.toEqual('');
};
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
});
it('propagates the matcher result when the promise is rejected', function(done) {
jasmine.getEnv().requirePromises();
env.it('a spec', function() {
return (
env
// eslint-disable-next-line compat/compat
.expectAsync(Promise.reject(new Error('nope')))
.already.toBeResolved()
);
});
var specExpectations = function(result) {
expect(result.status).toEqual('failed');
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(1);
expect(result.failedExpectations[0].message).toEqual(
'Expected a promise to be resolved but it was ' +
'rejected with Error: nope.'
);
expect(result.failedExpectations[0].matcherName)
.withContext('Matcher name')
.not.toEqual('');
};
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
});
it('fails when the promise is pending', function(done) {
jasmine.getEnv().requirePromises();
// eslint-disable-next-line compat/compat
var promise = new Promise(function() {});
env.it('a spec', function() {
return env.expectAsync(promise).already.toBeResolved();
});
var specExpectations = function(result) {
expect(result.status).toEqual('failed');
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(1);
expect(result.failedExpectations[0].message).toEqual(
'Expected a promise to be settled ' +
'(via expectAsync(...).already) but it was pending.'
);
expect(result.failedExpectations[0].matcherName)
.withContext('Matcher name')
.not.toEqual('');
};
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
});
});
});

View File

@@ -15,12 +15,19 @@ describe('toBeResolved', function() {
it('fails if the actual is rejected', function() {
jasmine.getEnv().requirePromises();
var matchersUtil = new jasmineUnderTest.MatchersUtil(),
var matchersUtil = new jasmineUnderTest.MatchersUtil({
pp: jasmineUnderTest.makePrettyPrinter([])
}),
matcher = jasmineUnderTest.asyncMatchers.toBeResolved(matchersUtil),
actual = Promise.reject('AsyncExpectationSpec rejection');
actual = Promise.reject(new Error('AsyncExpectationSpec rejection'));
return matcher.compare(actual).then(function(result) {
expect(result).toEqual(jasmine.objectContaining({ pass: false }));
expect(result).toEqual({
pass: false,
message:
'Expected a promise to be resolved but it was rejected ' +
'with Error: AsyncExpectationSpec rejection.'
});
});
});

View File

@@ -19,14 +19,15 @@ describe('#toBeResolvedTo', function() {
pp: jasmineUnderTest.makePrettyPrinter()
}),
matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(matchersUtil),
actual = Promise.reject('AsyncExpectationSpec error');
actual = Promise.reject(new Error('AsyncExpectationSpec error'));
return matcher.compare(actual, '').then(function(result) {
expect(result).toEqual(
jasmine.objectContaining({
pass: false,
message:
"Expected a promise to be resolved to '' but it was rejected."
"Expected a promise to be resolved to '' but it was rejected " +
'with Error: AsyncExpectationSpec error.'
})
);
});

View File

@@ -7,78 +7,6 @@ describe('matchersUtil', function() {
});
describe('equals', function() {
describe('Properties', function() {
var fc;
beforeEach(function() {
fc = jasmine.getEnv().requireFastCheck();
});
function basicAnythingSettings() {
return {
key: fc.oneof(fc.string(), fc.constantFrom('k1', 'k2', 'k3')),
// Limiting depth & number of keys allows fast-check to try
// a lot more scalar values.
maxDepth: 2,
maxKeys: 5,
withBoxedValues: true,
withMap: true,
withSet: true
};
}
function numRuns() {
var many = 5000000;
// Be thorough but very slow when specified (usually on CI).
if (process.env.JASMINE_LONG_PROPERTY_TESTS) {
/* eslint-disable-next-line no-console */
console.log(
'Using',
many,
'runs of fc.assert because JASMINE_LONG_PROPERTY_TESTS was set. This may take several minutes.'
);
return many;
} else {
return undefined;
}
}
it('is symmetric', function() {
var matchersUtil = new jasmineUnderTest.MatchersUtil();
fc.assert(
fc.property(
fc.anything(basicAnythingSettings()),
fc.anything(basicAnythingSettings()),
function(a, b) {
return matchersUtil.equals(a, b) === matchersUtil.equals(b, a);
}
),
{
numRuns: numRuns(),
examples: [[0, 5e-324]]
}
);
});
it('is reflexive', function() {
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var anythingSettings = basicAnythingSettings();
anythingSettings.withMap = false;
fc.assert(
fc.property(fc.dedup(fc.anything(anythingSettings), 2), function(
values
) {
return matchersUtil.equals(values[0], values[1]);
}),
{
numRuns: numRuns()
}
);
});
});
it('passes for literals that are triple-equal', function() {
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals(null, null)).toBe(true);
@@ -790,6 +718,154 @@ describe('matchersUtil', function() {
expect(matchersUtil.equals(buffer1, buffer2)).toBe(false);
});
describe('Typed arrays', function() {
it('fails for typed arrays of same length and contents but different types', function() {
var matchersUtil = new jasmineUnderTest.MatchersUtil();
// eslint-disable-next-line compat/compat
var a1 = new Int8Array(1);
// eslint-disable-next-line compat/compat
var a2 = new Uint8Array(1);
a1[0] = a2[0] = 0;
expect(matchersUtil.equals(a1, a2)).toBe(false);
});
// eslint-disable-next-line compat/compat
[
'Int8Array',
'Uint8Array',
'Uint8ClampedArray',
'Int16Array',
'Uint16Array',
'Int32Array',
'Uint32Array',
'Float32Array',
'Float64Array'
].forEach(function(typeName) {
function requireType() {
var TypedArrayCtor = jasmine.getGlobal()[typeName];
if (!TypedArrayCtor) {
pending('Browser does not support ' + typeName);
}
return TypedArrayCtor;
}
it(
'passes for ' + typeName + 's with same length and content',
function() {
var TypedArrayCtor = requireType();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var a1 = new TypedArrayCtor(2);
var a2 = new TypedArrayCtor(2);
a1[0] = a2[0] = 0;
a1[1] = a2[1] = 1;
expect(matchersUtil.equals(a1, a2)).toBe(true);
}
);
it('fails for ' + typeName + 's with different length', function() {
var TypedArrayCtor = requireType();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var a1 = new TypedArrayCtor(2);
var a2 = new TypedArrayCtor(1);
a1[0] = a1[1] = a2[0] = 0;
expect(matchersUtil.equals(a1, a2)).toBe(false);
});
it(
'fails for ' + typeName + 's with same length but different content',
function() {
var TypedArrayCtor = requireType();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var a1 = new TypedArrayCtor(1);
var a2 = new TypedArrayCtor(1);
a1[0] = 0;
a2[0] = 1;
expect(matchersUtil.equals(a1, a2)).toBe(false);
}
);
it('checks nonstandard properties of ' + typeName, function() {
var TypedArrayCtor = requireType();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var a1 = new TypedArrayCtor(1);
var a2 = new TypedArrayCtor(1);
a1[0] = a2[0] = 0;
a1.extra = 'yes';
expect(matchersUtil.equals(a1, a2)).toBe(false);
});
it('works with custom equality testers with ' + typeName, function() {
var TypedArrayCtor = requireType();
var a1 = new TypedArrayCtor(1);
var a2 = new TypedArrayCtor(1);
var matchersUtil = new jasmineUnderTest.MatchersUtil({
customTesters: [
function() {
return true;
}
]
});
a1[0] = 0;
a2[0] = 1;
expect(matchersUtil.equals(a1, a2)).toBe(true);
});
});
['BigInt64Array', 'BigUint64Array'].forEach(function(typeName) {
function requireType() {
var TypedArrayCtor = jasmine.getGlobal()[typeName];
if (!TypedArrayCtor) {
pending('Browser does not support ' + typeName);
}
return TypedArrayCtor;
}
it(
'passes for ' + typeName + 's with same length and content',
function() {
var TypedArrayCtor = requireType();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var a1 = new TypedArrayCtor(2);
var a2 = new TypedArrayCtor(2);
// eslint-disable-next-line compat/compat
a1[0] = a2[0] = BigInt(0);
// eslint-disable-next-line compat/compat
a1[1] = a2[1] = BigInt(1);
expect(matchersUtil.equals(a1, a2)).toBe(true);
}
);
it('fails for ' + typeName + 's with different length', function() {
var TypedArrayCtor = requireType();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var a1 = new TypedArrayCtor(2);
var a2 = new TypedArrayCtor(1);
// eslint-disable-next-line compat/compat
a1[0] = a1[1] = a2[0] = BigInt(0);
expect(matchersUtil.equals(a1, a2)).toBe(false);
});
it(
'fails for ' + typeName + 's with same length but different content',
function() {
var TypedArrayCtor = requireType();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var a1 = new TypedArrayCtor(2);
var a2 = new TypedArrayCtor(2);
// eslint-disable-next-line compat/compat
a1[0] = a1[1] = a2[0] = BigInt(0);
// eslint-disable-next-line compat/compat
a2[1] = BigInt(1);
expect(matchersUtil.equals(a1, a2)).toBe(false);
}
);
});
});
describe('when running in an environment with array polyfills', function() {
var findIndexDescriptor = Object.getOwnPropertyDescriptor(
Array.prototype,

View File

@@ -1,16 +0,0 @@
(function(env) {
var NODE_JS =
typeof process !== 'undefined' &&
process.versions &&
typeof process.versions.node === 'string';
env.requireFastCheck = function() {
if (!NODE_JS) {
env.pending(
"Property tests don't run in the browser. Use `npm test` to run them."
);
}
return require('fast-check');
};
})(jasmine.getEnv());

View File

@@ -606,7 +606,7 @@ describe('HtmlReporter', function() {
var suiteDetail = outerSuite.childNodes[0];
var suiteLink = suiteDetail.childNodes[0];
expect(suiteLink.innerHTML).toEqual('A Suite');
expect(suiteLink.getAttribute('href')).toEqual('?foo=bar&spec=A Suite');
expect(suiteLink.getAttribute('href')).toEqual('/?foo=bar&spec=A Suite');
var specs = outerSuite.childNodes[1];
var spec = specs.childNodes[0];
@@ -616,7 +616,7 @@ describe('HtmlReporter', function() {
var specLink = spec.childNodes[0];
expect(specLink.innerHTML).toEqual('with a spec');
expect(specLink.getAttribute('href')).toEqual(
'?foo=bar&spec=A Suite with a spec'
'/?foo=bar&spec=A Suite with a spec'
);
});
@@ -924,7 +924,7 @@ describe('HtmlReporter', function() {
var throwingExpectationsUI = container.querySelector('.jasmine-throw');
throwingExpectationsUI.click();
expect(navigateHandler).toHaveBeenCalledWith('throwFailures', true);
expect(navigateHandler).toHaveBeenCalledWith('oneFailurePerSpec', true);
});
it('should navigate and change the setting to off', function() {
@@ -953,7 +953,10 @@ describe('HtmlReporter', function() {
var throwingExpectationsUI = container.querySelector('.jasmine-throw');
throwingExpectationsUI.click();
expect(navigateHandler).toHaveBeenCalledWith('throwFailures', false);
expect(navigateHandler).toHaveBeenCalledWith(
'oneFailurePerSpec',
false
);
});
});
describe('UI for hiding disabled specs', function() {
@@ -1169,7 +1172,7 @@ describe('HtmlReporter', function() {
var seedBar = container.querySelector('.jasmine-seed-bar');
expect(seedBar.textContent).toBe(', randomized with seed 424242');
var seedLink = container.querySelector('.jasmine-seed-bar a');
expect(seedLink.getAttribute('href')).toBe('?seed=424242');
expect(seedLink.getAttribute('href')).toBe('/?seed=424242');
});
it('should not show the current seed bar if not randomizing', function() {
@@ -1218,7 +1221,7 @@ describe('HtmlReporter', function() {
reporter.jasmineDone({ order: { random: true } });
var skippedLink = container.querySelector('.jasmine-skipped a');
expect(skippedLink.getAttribute('href')).toEqual('?foo=bar&spec=');
expect(skippedLink.getAttribute('href')).toEqual('/?foo=bar&spec=');
});
});

View File

@@ -108,4 +108,56 @@ describe('npm package', function() {
false
);
});
it('does not have any unexpected files in the root directory', function() {
var files = fs.readdirSync(this.tmpDir);
expect(files).toEqual(['package']);
});
it('does not have any unexpected files in the package directory', function() {
var files = fs.readdirSync(path.resolve(this.tmpDir, 'package'));
files.sort();
expect(files).toEqual([
'MIT.LICENSE',
'README.md',
'images',
'lib',
'package.json'
]);
});
it('only has images in the images dir', function() {
var files = fs.readdirSync(path.resolve(this.tmpDir, 'package/images')),
i;
for (i = 0; i < files.length; i++) {
expect(files[i]).toMatch(/\.(svg|png)$/);
}
});
it('only has JS and CSS files in the lib dir', function() {
var files = [],
i;
function getFiles(dir) {
var dirents = fs.readdirSync(dir, { withFileTypes: true }),
j;
for (j = 0; j < dirents.length; j++) {
dirent = dirents[j];
if (dirent.isDirectory()) {
getFiles(path.resolve(dir, dirent.name));
} else {
files.push(path.resolve(dir, dirent.name));
}
}
}
getFiles(path.resolve(this.tmpDir, 'package/lib'));
for (i = 0; i < files.length; i++) {
expect(files[i]).toMatch(/\.(js|css)$/);
}
});
});

View File

@@ -27,7 +27,6 @@ module.exports = {
'helpers/domHelpers.js',
'helpers/integrationMatchers.js',
'helpers/promises.js',
'helpers/requireFastCheck.js',
'helpers/defineJasmineUnderTest.js',
'helpers/resetEnv.js'
],

View File

@@ -14,7 +14,6 @@
"helpers/domHelpers.js",
"helpers/integrationMatchers.js",
"helpers/promises.js",
"helpers/requireFastCheck.js",
"helpers/overrideConsoleLogForCircleCi.js",
"helpers/nodeDefineJasmineUnderTest.js",
"helpers/resetEnv.js"