diff --git a/.all-contributorsrc b/.all-contributorsrc index 9aec642d..c3fb313d 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -277,7 +277,9 @@ "avatar_url": "https://avatars2.githubusercontent.com/u/980783?v=4", "profile": "http://foss-geek.blogspot.com/", "contributions": [ - "code" + "code", + "test", + "doc" ] }, { diff --git a/README.md b/README.md index b2d6dae1..58a68c66 100644 --- a/README.md +++ b/README.md @@ -54,8 +54,10 @@ If you've come here to help contribute - Thanks! Take a look at the [contributin - [.toBeBoolean()](#tobeboolean) - [.toBeTrue()](#tobetrue) - [.toBeFalse()](#tobefalse) - - [~~Date~~](#date) - - [.toBeDate()](#tobedate) + - [Date](#date) + - [.toBeDate()](#tobedate) + - [.toBeValidDate()](#tobevaliddate) + - Further proposals in [#117](https://github.com/jest-community/jest-extended/issues/117) PRs welcome - [Function](#function) - [.toBeFunction()](#tobefunction) - [Mock](#mock) @@ -333,6 +335,20 @@ test('passes when value is a date', () => { }); ``` +### .toBeValidDate() + +Use `.toBeValidDate` when checking if a given `Date` object is valid. + +``` +test('passes when Date is valid', () => { + expect(new Date()).toBeValidDate(); + expect('01/01/2018').not.toBeValidDate(); + expect(new Date('01/01/2018').toBeValidDate(); + expect(new Date('01/90/2018').not.toBeValidDate(); + expect(undefined).not.toBeValidDate(); +}); +``` + ### Function #### .toBeFunction() diff --git a/src/matchers/index.js b/src/matchers/index.js index 0f6157b7..bfd9455e 100644 --- a/src/matchers/index.js +++ b/src/matchers/index.js @@ -44,6 +44,7 @@ import toBeSealed from './toBeSealed'; import toIncludeRepeated from './toIncludeRepeated'; import toHaveBeenCalledBefore from './toHaveBeenCalledBefore'; import toBeDate from './toBeDate'; +import toBeValidDate from './toBeValidDate'; export default [ toBeEven, @@ -91,5 +92,6 @@ export default [ toSatisfy, toIncludeRepeated, toHaveBeenCalledBefore, - toBeDate + toBeDate, + toBeValidDate ].reduce((acc, matcher) => ({ ...acc, ...matcher }), {}); diff --git a/src/matchers/toBeDate/index.test.js b/src/matchers/toBeDate/index.test.js index 19370a21..67d4bb8e 100644 --- a/src/matchers/toBeDate/index.test.js +++ b/src/matchers/toBeDate/index.test.js @@ -15,19 +15,12 @@ describe('.toBeDate', () => { }); describe('.not.toBeDate', () => { - each([ - [false], - [true], - [0], - [''], - [{}], - [() => {}], - [undefined], - [null], - [NaN] - ]).test('passes when not given a date: %s', given => { - expect(given).not.toBeDate(); - }); + each([[false], [true], [0], [''], [{}], [() => {}], [undefined], [null], [NaN]]).test( + 'passes when not given a date: %s', + given => { + expect(given).not.toBeDate(); + } + ); test('fails when given a date', () => { expect(() => expect(new Date('2018-01-01T13:00:00.000Z')).not.toBeDate()).toThrowErrorMatchingSnapshot(); diff --git a/src/matchers/toBeDate/predicate.js b/src/matchers/toBeDate/predicate.js index fe0d79ee..ad9154b4 100644 --- a/src/matchers/toBeDate/predicate.js +++ b/src/matchers/toBeDate/predicate.js @@ -1,11 +1,7 @@ -function is(type) { - return value => Object.prototype.toString.call(value) === `[object ${type}]`; -} +import { is } from '../../utils'; let hasDateType = is('Date'); -function isDate(value) { - return hasDateType(value) && !isNaN(value); -} +const isDate = value => hasDateType(value) && !isNaN(value); -export default expected => isDate(expected); +export default isDate; diff --git a/src/matchers/toBeValidDate/__snapshots__/index.test.js.snap b/src/matchers/toBeValidDate/__snapshots__/index.test.js.snap new file mode 100644 index 00000000..b445444e --- /dev/null +++ b/src/matchers/toBeValidDate/__snapshots__/index.test.js.snap @@ -0,0 +1,17 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`.not.toBeValidDate fails when given a valid date value 1`] = ` +"expect(received).not.toBeValidDate() + +Expected value to not be a valid date received: + 2018-01-01T13:00:00.000Z" +`; + +exports[`.toBeValidDate fails when given an invalid date 1`] = `"Invalid time value"`; + +exports[`.toBeValidDate fails when not given non-date values 1`] = ` +"expect(received).toBeValidDate() + +Expected value to be a valid date received: + 1" +`; diff --git a/src/matchers/toBeValidDate/index.js b/src/matchers/toBeValidDate/index.js new file mode 100644 index 00000000..01c52566 --- /dev/null +++ b/src/matchers/toBeValidDate/index.js @@ -0,0 +1,26 @@ +import { matcherHint, printReceived } from 'jest-matcher-utils'; + +import predicate from './predicate'; + +const passMessage = received => () => + matcherHint('.not.toBeValidDate', 'received', '') + + '\n\n' + + 'Expected value to not be a valid date received:\n' + + ` ${printReceived(received)}`; + +const failMessage = received => () => + matcherHint('.toBeValidDate', 'received', '') + + '\n\n' + + 'Expected value to be a valid date received:\n' + + ` ${printReceived(received)}`; + +export default { + toBeValidDate: expected => { + const pass = predicate(expected); + if (pass) { + return { pass: true, message: passMessage(expected) }; + } + + return { pass: false, message: failMessage(expected) }; + } +}; diff --git a/src/matchers/toBeValidDate/index.test.js b/src/matchers/toBeValidDate/index.test.js new file mode 100644 index 00000000..945a72f8 --- /dev/null +++ b/src/matchers/toBeValidDate/index.test.js @@ -0,0 +1,41 @@ +import each from 'jest-each'; + +import matcher from './'; + +expect.extend(matcher); + +describe('.toBeValidDate', () => { + test('passes when given a valid date', () => { + expect(new Date()).toBeValidDate(); + }); + + test('fails when given an invalid date', () => { + expect(() => expect(new Date('2018-90-90T13:00:00.000Z')).toBeValidDate()).toThrowErrorMatchingSnapshot(); + }); + + test('fails when not given non-date values', () => { + expect(() => expect(1).toBeValidDate()).toThrowErrorMatchingSnapshot(); + }); +}); + +describe('.not.toBeValidDate', () => { + each([ + [new Date('01/90/2018')], + [new Date('32/01/2018')], + [false], + [true], + [0], + [''], + [{}], + [() => {}], + [undefined], + [null], + [NaN] + ]).test('passes when not given a date: %s', given => { + expect(given).not.toBeValidDate(); + }); + + test('fails when given a valid date value', () => { + expect(() => expect(new Date('2018-01-01T13:00:00.000Z')).not.toBeValidDate()).toThrowErrorMatchingSnapshot(); + }); +}); diff --git a/src/matchers/toBeValidDate/predicate.js b/src/matchers/toBeValidDate/predicate.js new file mode 100644 index 00000000..1cf4c84e --- /dev/null +++ b/src/matchers/toBeValidDate/predicate.js @@ -0,0 +1,7 @@ +import { is } from '../../utils'; + +const hasDateType = is('Date'); + +const isValidDate = value => hasDateType(value) && !isNaN(value) && !isNaN(value.getTime()); + +export default isValidDate; diff --git a/src/matchers/toBeValidDate/predicate.test.js b/src/matchers/toBeValidDate/predicate.test.js new file mode 100644 index 00000000..e789dd62 --- /dev/null +++ b/src/matchers/toBeValidDate/predicate.test.js @@ -0,0 +1,24 @@ +import each from 'jest-each'; +import predicate from './predicate'; + +describe('toBeDate Predicate', () => { + test('returns true when given a valid date', () => { + expect(predicate(new Date('12/25/2017'))).toBe(true); + }); + + each([ + [new Date('01/90/2018')], + [new Date('32/01/2018')], + [true], + [false], + [''], + [0], + [{}], + [() => {}], + [undefined], + [null], + [NaN] + ]).test('returns false when given: %s', given => { + expect(predicate(given)).toBe(false); + }); +}); diff --git a/src/utils/index.js b/src/utils/index.js index 30b7e6e9..b062be8f 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -8,4 +8,6 @@ export const determinePropertyMessage = (actual, property, message = 'Not Access return actual && actual[property] ? actual[property] : message; }; +export const is = type => value => Object.prototype.toString.call(value) === `[object ${type}]`; + export { equals }; diff --git a/types/index.d.ts b/types/index.d.ts index 5ced45f1..89d8cd35 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -86,10 +86,15 @@ declare namespace jest { toBeFalse(): R; /** - * Use .toBeDate when checking if a value is a Date. + * Use `.toBeDate` when checking if a value is a `Date`. */ toBeDate(): R; + /** + * Use `.toBeValidDate` when checking if a value is a `valid Date`. + */ + toBeValidDate(): R; + /** * Use `.toBeFunction` when checking if a value is a `Function`. */ @@ -301,4 +306,3 @@ declare namespace jest { toIncludeMultiple(substring: string[]): R; } } -