├── .bowerrc
├── .gitignore
├── .npmignore
├── specs
├── nodejs
│ └── jasmine2-custom-message.spec.js
├── protractor
│ ├── conf.js
│ └── test-jasmine2-custom-message.js
├── browser
│ ├── styles.css
│ └── index.html
└── common
│ ├── expect-message-to-equal.js
│ └── test-jasmine2-custom-message.js
├── .jshintrc
├── bower.json
├── LICENSE
├── Gruntfile.js
├── package.json
├── jasmine2-custom-message.d.ts
├── jasmine2-custom-message.js
└── README.md
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "node_modules"
3 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | bower_components
3 | npm-debug.log
4 | tmp
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .jshintrc
2 | .npmignore
3 | .idea
4 | bower_components
5 | docs
6 | specs
7 | Gruntfile.js
8 | bower.json
9 |
--------------------------------------------------------------------------------
/specs/nodejs/jasmine2-custom-message.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var path = '../common/';
4 |
5 | require(path + 'expect-message-to-equal');
6 | require('../../jasmine2-custom-message');
7 | require(path + 'test-jasmine2-custom-message');
--------------------------------------------------------------------------------
/specs/protractor/conf.js:
--------------------------------------------------------------------------------
1 | var colors = require('colors');
2 | colors.enabled = true;
3 |
4 | exports.config = {
5 | framework: 'jasmine2',
6 | specs: ['../nodejs/jasmine2-custom-message.spec.js', './test-jasmine2-custom-message.js'],
7 | };
8 |
--------------------------------------------------------------------------------
/specs/browser/styles.css:
--------------------------------------------------------------------------------
1 | .custom-message {
2 | display: block;
3 | }
4 |
5 | .color-scheme {
6 | margin-left: 20px;
7 | }
8 |
9 | .message-diff {
10 | margin-left: 40px;
11 | padding: 5px;
12 | background: white;
13 | font-size: 16px;
14 | }
15 |
16 | .color-addition {
17 | color: #007632;
18 | }
19 |
20 | .color-deletion {
21 | color: #9b0013;
22 | }
23 |
24 | .color-common {
25 | color: gray;
26 | }
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "curly": true,
3 | "eqeqeq": true,
4 | "immed": true,
5 | "latedef": true,
6 | "noarg": true,
7 | "sub": true,
8 | "undef": true,
9 | "boss": true,
10 | "eqnull": true,
11 | "node": true,
12 |
13 | "newcap": false,
14 | "evil": true,
15 | "globals": {
16 | "window": false,
17 | "document": false,
18 | "jasmine": false,
19 | "describe": false,
20 | "xdescribe": false,
21 | "it": false,
22 | "xit": false,
23 | "expect": false,
24 | "expectMessageToEqual": false,
25 | "since": false,
26 | "protractor": false
27 | }
28 | }
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jasmine2-custom-message",
3 | "description": "custom failure message on any jasmine assertion",
4 | "version": "0.8.2",
5 | "homepage": "https://github.com/avrelian/jasmine-custom-message",
6 | "authors": [{
7 | "name": "Sergey Radchenko",
8 | "email": "avrelian@yandex.ru",
9 | "homepage": "https://github.com/avrelian"
10 | }],
11 | "repository": {
12 | "type": "git",
13 | "url": "git@github.com:avrelian/jasmine2-custom-message.git"
14 | },
15 | "main": "jasmine2-custom-message.js",
16 | "devDependencies": {
17 | "jasmine-2.0.0": "https://github.com/pivotal/jasmine.git#2.0.0"
18 | },
19 | "keywords": [
20 | "jasmine",
21 | "error message",
22 | "failure message",
23 | "custom message"
24 | ],
25 | "license": "MIT",
26 | "ignore": [
27 | "**/.*",
28 | "node_modules",
29 | "bower_components",
30 | "docs",
31 | "specs",
32 | "Gruntfile.js"
33 | ]
34 | }
35 |
--------------------------------------------------------------------------------
/specs/browser/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | jasmine2-custom-message test for jasmine v2
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Sergey Radchenko
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function(grunt) {
4 |
5 | grunt.initConfig({
6 |
7 | jshint: {
8 | all: [
9 | 'jasmine2-custom-message.js',
10 | 'Gruntfile.js',
11 | 'specs/**/*.js'
12 | ],
13 | options: {
14 | jshintrc: '.jshintrc'
15 | }
16 | },
17 |
18 | jasmine_node: {
19 | // options have no effect in `grunt-jasmine-node`#v0.1.0
20 | test: {}
21 | },
22 |
23 | protractor: {
24 | options: {
25 | },
26 | jasmine_custom_message: {
27 | options: {
28 | configFile: 'specs/protractor/conf.js',
29 | args: {
30 | verbose: true
31 | }
32 | }
33 | }
34 | }
35 |
36 | });
37 |
38 | grunt.loadNpmTasks('grunt-contrib-jshint');
39 | grunt.loadNpmTasks('grunt-jasmine-node');
40 | grunt.loadNpmTasks('grunt-protractor-runner');
41 |
42 | // `jasmine-node` does not yet support `jasmine`#v2.0.0
43 | // To test `jsamine-custom-message` you can use a browser
44 | grunt.registerTask('test', ['jshint','protractor']);
45 |
46 | grunt.registerTask('default', ['test']);
47 |
48 | };
49 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jasmine2-custom-message",
3 | "description": "custom failure message on any jasmine assertion",
4 | "version": "0.9.4",
5 | "homepage": "https://github.com/avrelian/jasmine2-custom-message",
6 | "author": {
7 | "name": "Sergey Radchenko",
8 | "email": "avrelian@yandex.ru",
9 | "url": "https://github.com/avrelian"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git@github.com:avrelian/jasmine2-custom-message.git"
14 | },
15 | "bugs": {
16 | "url": "https://github.com/avrelian/jasmine2-custom-message/issues"
17 | },
18 | "licenses": [
19 | {
20 | "type": "MIT",
21 | "url": "https://github.com/avrelian/jasmine2-custom-message/blob/master/LICENSE"
22 | }
23 | ],
24 | "main": "jasmine2-custom-message.js",
25 | "engines": {
26 | "node": ">= 0.8.0"
27 | },
28 | "scripts": {
29 | "test": "grunt test",
30 | "pretest": "webdriver-manager update"
31 | },
32 | "devDependencies": {
33 | "diff": "~3.5.0",
34 | "es5-shim": "~4.0.0",
35 | "jasmine": "~2.2.1",
36 | "grunt": "~0.4.2",
37 | "grunt-contrib-jshint": "~0.6.0",
38 | "grunt-jasmine-node": "~0.1.0",
39 | "grunt-protractor-runner": "^5.0.0",
40 | "colors": "~1.1.2"
41 | },
42 | "keywords": [
43 | "jasmine",
44 | "error message",
45 | "failure message",
46 | "custom message"
47 | ],
48 | "types": "./jasmine2-custom-message.d.ts"
49 | }
50 |
--------------------------------------------------------------------------------
/jasmine2-custom-message.d.ts:
--------------------------------------------------------------------------------
1 | // Type definitions for Jasmine2 custom messages
2 | // Project: https://github.com/avrelian/jasmine2-custom-message
3 | // Definitions by: Holger Jeromin
4 | // Definitions: https://github.com/avrelian/jasmine2-custom-message
5 |
6 | ///
7 |
8 | interface Jasmine2CustomMessageFncParam {
9 | /** The actual value */
10 | actual: any,
11 | /** The expected value */
12 | expected: any
13 | }
14 |
15 | interface ExpectWrapper {
16 | /**
17 | * Create an expectation for a spec.
18 | * @param spy
19 | */
20 | expect(spy: Function): jasmine.Matchers;
21 |
22 | /**
23 | * Create an expectation for a spec.
24 | * @param actual
25 | */
26 | expect(actual: ArrayLike): jasmine.ArrayLikeMatchers;
27 |
28 | /**
29 | * Create an expectation for a spec.
30 | * @param actual Actual computed value to test expectations against.
31 | */
32 | expect(actual: T): jasmine.Matchers;
33 |
34 | /**
35 | * Create an expectation for a spec.
36 | */
37 | expect(): jasmine.NothingMatcher;
38 | }
39 |
40 | /**
41 | * Add a dynamic custom message.
42 | * The original message from jasmine is available as this.message
43 | * The return value will be converted with toString()
44 | * If it is already a string #{actual} and #{expected} will be replaced with the current values.
45 | * #{message} will be replaced with the original message from jasmine.
46 | */
47 | declare function since(messageGenerator: (this: Jasmine2CustomMessageFncParam) => any): ExpectWrapper;
48 | /**
49 | * Add a custom message.
50 | * #{actual} and #{expected} will be replaced with the current values.
51 | * #{message} will be replaced with the original message from jasmine.
52 | */
53 | declare function since(message: string): ExpectWrapper;
54 | /**
55 | * Add a static custom message.
56 | */
57 | declare function since(message: number | boolean): ExpectWrapper;
58 |
59 | /**
60 | * Add a static custom message.
61 | * The text will be generated from toString() or JSON.stringify()
62 | */
63 | declare function since(message: any): ExpectWrapper;
64 |
--------------------------------------------------------------------------------
/jasmine2-custom-message.js:
--------------------------------------------------------------------------------
1 | /*
2 | * jasmine2-custom-message
3 | * https://github.com/avrelian/jasmine2-custom-message
4 | *
5 | * Copyright (c) 2014 Sergey Radchenko
6 | * Licensed under the MIT license.
7 | */
8 |
9 | (function(global) {
10 | 'use strict';
11 |
12 | if (! (global.jasmine && global.expect)) {
13 | return;
14 | }
15 |
16 | var ofType = function(val) {
17 | var types = [].slice.call(arguments, 1);
18 | var valType = val === null ? 'null' : typeof val;
19 | return types.indexOf(valType) > -1;
20 | };
21 |
22 | var formatString = function(data, message) {
23 | if (
24 | (
25 | data.matcherName === "toHaveBeenCalled" ||
26 | data.matcherName === "toHaveBeenCalledTimes"
27 | ) &&
28 | data.actual &&
29 | data.actual.calls &&
30 | typeof data.actual.calls.count === 'function'
31 | ) {
32 | message = message.replace(/#\{actual\}/g, data.actual.calls.count());
33 | } else {
34 | message = message.replace(/#\{actual\}/g, data.actual);
35 | }
36 | message = message.replace(/#\{expected\}/g, data.expected);
37 | message = message.replace(/#\{message\}/g, data.message);
38 | return message;
39 | };
40 |
41 | var getMessage = function(data, message) {
42 |
43 | while (! ofType(message, 'string', 'number', 'boolean')) {
44 | switch (true) {
45 | case ofType(message, 'undefined', 'null'):
46 | message = data.message || 'You cannot use `' + message + '` as a custom message';
47 | break;
48 | case ofType(message, 'function'):
49 | message = message.call(data);
50 | break;
51 | case message && ofType(message.toString, 'function') && message.toString().indexOf('[object ') !== 0:
52 | message = message.toString();
53 | break;
54 | case JSON && ofType(JSON.stringify, 'function'):
55 | message = JSON.stringify(message);
56 | break;
57 | default:
58 | message = 'N/A';
59 | }
60 | }
61 |
62 | if (ofType(message, 'string')) {
63 | return formatString(data, message);
64 | }
65 |
66 | return message.toString();
67 | };
68 |
69 | var wrapAddExpectationResult = function(addExpectationResult, customMessage) {
70 | return function(passed, data) {
71 | data.message = getMessage(data, customMessage);
72 | addExpectationResult(passed, data);
73 | };
74 | };
75 |
76 | var wrapExpect = function(expect, customMessage) {
77 | return function(actual) {
78 | var assertion = expect(actual);
79 | assertion.addExpectationResult = assertion.not.addExpectationResult = wrapAddExpectationResult(assertion.addExpectationResult, customMessage);
80 | return assertion;
81 | };
82 | };
83 |
84 | global.since = function(customMessage) {
85 | return {
86 | expect: wrapExpect(global.expect, customMessage)
87 | };
88 | };
89 |
90 | if (typeof module !== 'undefined' && typeof module.exports === 'object') {
91 | module.exports = global.since;
92 | }
93 |
94 | return global.since;
95 | })((function(){return this;})());
96 |
--------------------------------------------------------------------------------
/specs/common/expect-message-to-equal.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | (function() {
4 | var global = Function('return this')();
5 | if(! (global.jasmine && global.expect)) {
6 | return;
7 | }
8 |
9 | var isBrowserEnv = global.window && global === global.window;
10 | var isCommonJS = typeof module !== 'undefined' && typeof module.exports === 'object';
11 |
12 | var diff;
13 | if (isBrowserEnv) {
14 | diff = window.JsDiff;
15 | } else {
16 | if (isCommonJS) {
17 | diff = require('diff');
18 | }
19 | }
20 |
21 |
22 | var getMessage = function(actualMessage, expectedMessage) {
23 | actualMessage = actualMessage ? actualMessage.toString() : '';
24 | expectedMessage = expectedMessage ? expectedMessage.toString() : '';
25 |
26 | var colorize = function(value, color) {
27 | if (value.value) {
28 | value = value.value;
29 | }
30 | if (isBrowserEnv) {
31 | return '' + value + '';
32 | } else {
33 | if (isCommonJS) {
34 | var colors = {
35 | addition: 'cyan',
36 | deletion: 'yellow',
37 | common: 'grey'
38 | };
39 | return value[colors[color]];
40 | }
41 | }
42 | return value;
43 | };
44 |
45 | var colorScheme = [
46 | ['with', 'common'],
47 | ['additions', 'addition'],
48 | ['and', 'common'],
49 | ['deletions', 'deletion']
50 | ].map(function(item) {
51 | return colorize(item[0], item[1]);
52 | }).join(' ');
53 |
54 | var messagesDiff = function() {
55 | if (typeof 'a'[0] === 'undefined') {
56 | // this browser does not support ES5 bracket notation on a string
57 | return colorize(expectedMessage, 'deletion') + '
' + colorize(actualMessage, 'addition');
58 | }
59 |
60 | return diff.diffChars(expectedMessage, actualMessage).reduce(function(result, part) {
61 | var color = part.added ? 'addition' : part.removed ? 'deletion' : 'common';
62 | return result + colorize(part, color);
63 | }, '');
64 | };
65 |
66 | var createMessage = function(prompt, colorScheme, messagesDiff) {
67 | if (isBrowserEnv) {
68 | var el = document.createElement('div');
69 | el.className = 'custom-message';
70 | el.innerHTML = '' + prompt + '
' +
71 | '' + colorScheme + ':
' +
72 | '' + messagesDiff + '
';
73 | return el;
74 | }
75 |
76 | return prompt + ' ' + colorScheme + ':\n\t' + messagesDiff;
77 | };
78 |
79 | return createMessage('See diff of expected and actual message', colorScheme, messagesDiff());
80 | };
81 |
82 | var wrapAddExpectationResult = function(assertion) {
83 | assertion.addExpectationResult = assertion.not.addExpectationResult = (function(addExpectationResult) {
84 | return function(passed, data) {
85 | if (data.message === assertion.expectedMessage) {
86 | passed = true;
87 | data.passed = true;
88 | delete data.message;
89 | } else {
90 | data.message = getMessage(data.message, assertion.expectedMessage);
91 | }
92 |
93 | addExpectationResult(passed, data);
94 | };
95 | })(assertion.addExpectationResult);
96 | };
97 |
98 | var wrapGlobalExpect = function() {
99 | global.expect = (function(expect) {
100 | return function(actual) {
101 | var assertion = expect(actual);
102 | wrapAddExpectationResult(assertion);
103 | return assertion;
104 | };
105 | })(global.expect);
106 | };
107 |
108 | var wrapExpect = function(expect, expectedMessage) {
109 | return function(actual) {
110 | var assertion = expect(actual);
111 | assertion.expectedMessage = expectedMessage.toString();
112 | return assertion;
113 | };
114 | };
115 |
116 | var wrapSince = function(since, expectedMessage) {
117 | return function(customMessage) {
118 | var sinceObj = since(customMessage);
119 | sinceObj.expect = wrapExpect(sinceObj.expect, expectedMessage);
120 | return sinceObj;
121 | };
122 | };
123 |
124 | var defineExpectMessageToEqual = function() {
125 | global.expectMessageToEqual = function(expectedMessage) {
126 | return {
127 | since: wrapSince(global.since, expectedMessage),
128 | expect: wrapExpect(global.expect, expectedMessage)
129 | };
130 | };
131 | };
132 |
133 | var init = function() {
134 | wrapGlobalExpect();
135 | defineExpectMessageToEqual();
136 | };
137 |
138 |
139 | if (isBrowserEnv) {
140 | init();
141 | } else {
142 | if (isCommonJS) {
143 | module.exports = init();
144 | }
145 | }
146 | })();
--------------------------------------------------------------------------------
/specs/protractor/test-jasmine2-custom-message.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('../common/expect-message-to-equal');
4 | require('../../jasmine2-custom-message');
5 |
6 | (function(undefined) {
7 | var global = Function('return this')();
8 | var isBrowserEnv = global.window && global === global.window;
9 | var isCommonJS = typeof module !== 'undefined' && module.exports;
10 |
11 | var expectMessageToEqual = global.expectMessageToEqual;
12 |
13 | var test = function() {
14 |
15 | describe('jasmine with jasmine2-custom-message', function() {
16 |
17 | describe('should generate custom failure message', function() {
18 |
19 | describe('when actual value is', function() {
20 |
21 | describe('a fulfilled promise', function() {
22 |
23 | describe('and expectation is matching', function() {
24 |
25 | it('positively', function() {
26 | expectMessageToEqual("2 bla-bla-bla 3").
27 | since(function() {
28 | return this.expected + ' bla-bla-bla ' + this.actual;
29 | }).
30 | expect(protractor.promise.fulfilled(3)).toEqual(2);
31 | });
32 |
33 | it('negatively', function() {
34 | expectMessageToEqual("3 bla-bla-bla 3").
35 | since(function() {
36 | return this.expected + ' bla-bla-bla ' + this.actual;
37 | }).
38 | expect(protractor.promise.fulfilled(3)).not.toEqual(3);
39 | });
40 |
41 | describe('and original message is included', function() {
42 | it('positively', function() {
43 | expectMessageToEqual("2 bla-bla-bla 3, that is, Expected 3 to equal 2.").
44 | since(function() {
45 | return this.expected + ' bla-bla-bla ' + this.actual + ', that is, ' + this.message;
46 | }).
47 | expect(protractor.promise.fulfilled(3)).toEqual(2);
48 | });
49 |
50 | it('negatively', function() {
51 | expectMessageToEqual("3 bla-bla-bla 3, that is, Expected 3 not to equal 3.").
52 | since(function() {
53 | return this.expected + ' bla-bla-bla ' + this.actual + ', that is, ' + this.message;
54 | }).
55 | expect(protractor.promise.fulfilled(3)).not.toEqual(3);
56 | });
57 | });
58 |
59 | });
60 |
61 | describe('and expected value is', function() {
62 |
63 | describe('a fulfilled promise', function() {
64 |
65 | describe('and expectation is matching', function() {
66 |
67 | it('positively', function() {
68 | expectMessageToEqual("2 bla-bla-bla 3").
69 | since(function() {
70 | return this.expected + ' bla-bla-bla ' + this.actual;
71 | }).
72 | expect(protractor.promise.fulfilled(3)).toEqual(protractor.promise.fulfilled(2));
73 | });
74 |
75 | it('negatively', function() {
76 | expectMessageToEqual("3 bla-bla-bla 3").
77 | since(function() {
78 | return this.expected + ' bla-bla-bla ' + this.actual;
79 | }).
80 | expect(protractor.promise.fulfilled(3)).not.toEqual(protractor.promise.fulfilled(3));
81 | });
82 |
83 | describe('and original message is included', function() {
84 | it('positively', function() {
85 | expectMessageToEqual("2 bla-bla-bla 3, that is, Expected 3 to equal 2.").
86 | since(function() {
87 | return this.expected + ' bla-bla-bla ' + this.actual + ', that is, ' + this.message;
88 | }).
89 | expect(protractor.promise.fulfilled(3)).toEqual(protractor.promise.fulfilled(2));
90 | });
91 |
92 | it('negatively', function() {
93 | expectMessageToEqual("3 bla-bla-bla 3, that is, Expected 3 not to equal 3.").
94 | since(function() {
95 | return this.expected + ' bla-bla-bla ' + this.actual + ', that is, ' + this.message;
96 | }).
97 | expect(protractor.promise.fulfilled(3)).not.toEqual(protractor.promise.fulfilled(3));
98 | });
99 | });
100 | });
101 |
102 | });
103 |
104 | });
105 |
106 | });
107 |
108 | });
109 |
110 | });
111 |
112 | });
113 |
114 | };
115 |
116 | if (isBrowserEnv) {
117 | test();
118 | } else {
119 | if (isCommonJS) {
120 | module.exports = test();
121 | }
122 | }
123 | })();
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | jasmine2-custom-message
2 | ======================
3 | > **works with `jasmine v2`** (for work with `jasmine v1.3` see [jasmine-custom-message](https://github.com/avrelian/jasmine-custom-message))
4 |
5 |
6 | This script makes it possible to use your own failure message on any jasmine assertion.
7 |
8 | #### Example
9 |
10 | ```js
11 | describe('the story', function() {
12 | it('should finish ok', function() {
13 | since('all cats are grey in the dark').
14 | expect('tiger').toEqual('kitty'); // => 'all cats are grey in the dark'
15 | });
16 | });
17 | ```
18 |
19 |
20 | ## Simple
21 |
22 | All the magic happens in `since` function. That returns an object with a property `expect`. That contains no more than a wrapped jasmine `expect` function. That returns jasmine `expectation` object with a wrapped `addExpectationResult` function. That can replace an ordinary jasmine failure message with a newly generated one. That is generating based on a custom message you have supplied to `since` function as the first argument. That can be a primitive (except `null` and `undefined`), a function, or any other object. That is it.
23 |
24 | #### Example
25 |
26 | ```js
27 | describe('test', function() {
28 | it('should be ok', function() {
29 | since(function() {
30 | return {'tiger': 'kitty'};
31 | }).
32 | expect(3).toEqual(4); // => '{"tiger":"kitty"}'
33 | });
34 | });
35 | ```
36 |
37 |
38 | ## Unobtrusive
39 |
40 | You can use jasmine as you did before, since `jasmine2-custom-message` does not replace global jasmine `expect` function.
41 |
42 | #### Example
43 |
44 | ```js
45 | describe('test', function() {
46 | it('should be ok', function() {
47 | expect(3).toEqual(4); // => ordinary jasmine message
48 | });
49 | });
50 | ```
51 |
52 |
53 | ## Powerful
54 |
55 | You can use expected and actual values of the assertion in your custom message by:
56 |
57 | * Passing a function, and using `this.actual` and `this.expected`
58 | * Passing a string, and using `#{actual}` and `#{expected}`
59 |
60 | You can include the full original message from Jasmine by:
61 |
62 | * Passing a function, and using `this.message`
63 | * Passing a string, and using `#{message}`
64 |
65 | #### Examples using a function
66 |
67 | ```js
68 | describe('test', function() {
69 | it('should be ok', function() {
70 | since(function() {
71 | return this.actual + ' =/= ' + this.expected;
72 | }).
73 | expect(3).toEqual(4); // => '3 =/= 4'
74 | });
75 | });
76 | ```
77 |
78 | ```js
79 | describe('multiple tests that need some context added to the message', function() {
80 | it('should be ok for all options', function() {
81 | // passes the 1st loop iteration, fails the 2nd
82 | [1, 2, 3, 4, 5].forEach(testOptionIndex => {
83 | since(function() {
84 | return 'for test option ' + testOptionIndex + ': ' + this.message;
85 | }).
86 | expect(testOptionIndex).toEqual(1); // => for test option 2: Expected 2 to equal 1.
87 | });
88 | });
89 | });
90 | ```
91 |
92 | #### Example using a string
93 |
94 | ```js
95 | describe('test', function() {
96 | it('should be ok', function() {
97 | since('#{actual} =/= #{expected}').
98 | expect(3).toEqual(4); // => '3 =/= 4'
99 | });
100 | });
101 | ```
102 |
103 | ```js
104 | describe('multiple tests that need some context added to the message', function() {
105 | it('should be ok for all options', function() {
106 | // passes the 1st loop iteration, fails the 2nd
107 | [1, 2, 3, 4, 5].forEach(testOptionIndex => {
108 | since('for test option ' + testOptionIndex + ': #{message}').
109 | expect(testOptionIndex).toEqual(1); // => for test option 2: Expected 2 to equal 1.
110 | });
111 | });
112 | });
113 | ```
114 |
115 | ## Front-end usage
116 | * install the bower package from github
117 | ```
118 | bower install jasmine2-custom-message --save-dev
119 | ```
120 | * include `jasmine2-custom-message.js` into your HTML file next to `jasmine` script
121 | ```html
122 |
123 |
124 | ```
125 |
126 | ## Node.js usage
127 |
128 | * install the bower package from github
129 | ```
130 | $ bower install jasmine2-custom-message --save-dev
131 | ```
132 |
133 | or
134 | ```
135 | $ npm install jasmine2-custom-message --save-dev
136 | ```
137 |
138 | * require it in your spec file before your tests
139 | ```js
140 | require('jasmine2-custom-message');
141 | ```
142 | * or be explicit in any functional scope
143 | ```js
144 | var since = require('jasmine2-custom-message');
145 | ```
146 |
147 | ## Change log
148 |
149 | v0.9.0 - 2018.03.01
150 |
151 | * improved "format string" functionality: `#{message}` added for the original jasmine2 error message (kudos to Keith Zimmerman)
152 | * corrected output for `toHaveBeenCalled` matcher (kudos to Holger Jeromin)
153 | * updated `protractor` environment (kudos to Keith Zimmerman)
154 | * added `typescript` definitions (kudos to Holger Jeromin and Andrew N Marshall)
155 | * updated specs
156 |
157 | v0.8.0 - 2015.08.05
158 |
159 | * implemented "format string" functionality: `#{actual}` and `#{expected}`
160 | * configured `protractor` environment
161 | * corrected displaying of colors in tests running through `protractor`
162 | * updated specs
163 |
164 | v0.7.0 - 2014.10.23
165 |
166 | * fixed issue with custom failure messages on inverse assertions
167 | * updated specs
168 |
169 | `v0.6.0` - 2014.01.18 - **BROKEN COMPATIBILITY!**
170 | * all the magic moved into newly introduced `since` function
171 | * restored automatic initiation of the script upon inclusion (browser) or require (Node.js)
172 | * cleaned specs
173 |
174 | `v0.5.0` - 2014.01.15
175 | * added support for nested message functions
176 | * dropped automatic wrapping of jasmine `it` and `expect` functions in browsers
177 | * added specs for Node.js
178 | * added specs for browsers
179 | * registered bower package
180 | * made disambiguation and readability improvements
181 |
182 | `v0.2.0` - 2014.01.10
183 | * BROKEN COMPATIBILITY: custom messages is supplied as the third argument for jasmine `it` function
184 |
185 | `v0.1.0` - 2014.01.08
186 | * the first functional version
187 |
188 |
189 | ## Release plan
190 |
191 | `v1.0.0` - some new features and updates (based on requests from Issues)
192 |
--------------------------------------------------------------------------------
/specs/common/test-jasmine2-custom-message.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | (function(undefined) {
4 | var global = Function('return this')();
5 | var isBrowserEnv = global.window && global === global.window;
6 | var isCommonJS = typeof module !== 'undefined' && module.exports;
7 |
8 | var expectMessageToEqual = global.expectMessageToEqual;
9 |
10 | var test = function() {
11 |
12 | describe('jasmine with jasmine2-custom-message', function () {
13 |
14 | describe('should work as it did before', function() {
15 |
16 | it('with one assertion', function() {
17 | expectMessageToEqual("Expected 3 to equal 2.").
18 | expect(3).toEqual(2);
19 | });
20 |
21 | it('with number of assertions', function() {
22 | expectMessageToEqual("Expected 3 to equal 2.").
23 | expect(3).toEqual(2);
24 |
25 | expectMessageToEqual("Expected 3 to equal 2.").
26 | expect(3).toEqual(2);
27 |
28 | expectMessageToEqual("Expected 3 to equal 2.").
29 | expect(3).toEqual(2);
30 | });
31 |
32 | it('with inverse assertion', function() {
33 | expectMessageToEqual("Expected 2 not to equal 2.").
34 | expect(2).not.toEqual(2);
35 | });
36 |
37 | });
38 |
39 | describe('should generate', function() {
40 |
41 | describe('custom failure message when it is supplied', function() {
42 |
43 | describe('with a', function() {
44 |
45 | describe('string', function() {
46 |
47 | it('without replacements', function() {
48 | expectMessageToEqual("bla-bla-bla").
49 | since('bla-bla-bla').
50 | expect(3).toEqual(2);
51 | });
52 |
53 | it('containing #{actual} and #{expected} replacements', function() {
54 | expectMessageToEqual("2 bla-bla-bla 3").
55 | since('#{expected} bla-bla-bla #{actual}').
56 | expect(3).toEqual(2);
57 | });
58 |
59 | it('containing #{actual}, #{expected}, and #{message} replacements', function() {
60 | expectMessageToEqual("2 bla-bla-bla 3, that is, Expected 3 to equal 2.").
61 | since('#{expected} bla-bla-bla #{actual}, that is, #{message}').
62 | expect(3).toEqual(2);
63 | });
64 |
65 | });
66 |
67 | it('number', function() {
68 | expectMessageToEqual(5).
69 | since(5).
70 | expect(3).toEqual(2);
71 | });
72 |
73 | it('boolean', function() {
74 | expectMessageToEqual(false).
75 | since(false).
76 | expect(3).toEqual(2);
77 | });
78 |
79 |
80 | describe('function returning a', function() {
81 |
82 | describe('string', function() {
83 |
84 | it('concatenating with expected and actual properties', function() {
85 | expectMessageToEqual("2 bla-bla-bla 3").
86 | since(function() {
87 | return this.expected + ' bla-bla-bla ' + this.actual;
88 | }).
89 | expect(3).toEqual(2);
90 | });
91 |
92 | it('concatenating with expected, actual, and message properties', function() {
93 | expectMessageToEqual("2 bla-bla-bla 3, that is, Expected 3 to equal 2.").
94 | since(function() {
95 | return this.expected + ' bla-bla-bla ' + this.actual + ', that is, ' + this.message;
96 | }).
97 | expect(3).toEqual(2);
98 | });
99 |
100 | it('containing #{actual} and #{expected} replacements', function() {
101 | expectMessageToEqual("2 bla-bla-bla 3").
102 | since(function() {
103 | return '#{expected} bla-bla-bla #{actual}';
104 | }).
105 | expect(3).toEqual(2);
106 | });
107 |
108 | it('containing #{actual}, #{expected}, and #{message} replacements', function() {
109 | expectMessageToEqual("2 bla-bla-bla 3, that is, Expected 3 to equal 2.").
110 | since(function() {
111 | return '#{expected} bla-bla-bla #{actual}, that is, #{message}';
112 | }).
113 | expect(3).toEqual(2);
114 | });
115 |
116 | });
117 |
118 | it('number', function() {
119 | expectMessageToEqual(5).
120 | since(function() {
121 | return 5;
122 | }).
123 | expect(3).toEqual(2);
124 | });
125 |
126 | it('boolean', function() {
127 | expectMessageToEqual(false).
128 | since(function() {
129 | return false;
130 | }).
131 | expect(3).toEqual(2);
132 | });
133 |
134 |
135 | describe('another function returning a', function() {
136 |
137 | describe('string', function() {
138 |
139 | it('concatenating with expected and actual properties', function() {
140 | expectMessageToEqual("2 bla-bla-bla 3").
141 | since(function() {
142 | return function() {
143 | return this.expected + ' bla-bla-bla ' + this.actual;
144 | };
145 | }).
146 | expect(3).toEqual(2);
147 | });
148 |
149 | it('containing #{actual} and #{expected} replacements', function() {
150 | expectMessageToEqual("2 bla-bla-bla 3").
151 | since(function() {
152 | return function() {
153 | return '#{expected} bla-bla-bla #{actual}';
154 | };
155 | }).
156 | expect(3).toEqual(2);
157 | });
158 |
159 | });
160 |
161 | it('number', function() {
162 | expectMessageToEqual(5).
163 | since(function() {
164 | return function() {
165 | return 5;
166 | };
167 | }).
168 | expect(3).toEqual(2);
169 | });
170 |
171 | it('boolean', function() {
172 | expectMessageToEqual(false).
173 | since(function() {
174 | return function() {
175 | return false;
176 | };
177 | }).
178 | expect(3).toEqual(2);
179 | });
180 |
181 | it('an object', function() {
182 | expectMessageToEqual('{"someProp":"someVal"}').
183 | since(function() {
184 | return function() {
185 | return {someProp: 'someVal'};
186 | };
187 | }).
188 | expect(3).toEqual(2);
189 | });
190 |
191 | });
192 |
193 | });
194 |
195 |
196 | describe('object', function() {
197 |
198 | var someObj = {someProp: 'someVal'};
199 |
200 | it('without overridden toString method', function() {
201 | expectMessageToEqual('{"someProp":"someVal"}').
202 | since(someObj).
203 | expect(3).toEqual(2);
204 | });
205 |
206 | describe('with overridden toString method', function() {
207 |
208 | it('without replacements', function() {
209 | someObj.toString = function() {
210 | return 'object bla-bla-bla';
211 | };
212 |
213 | expectMessageToEqual("object bla-bla-bla").
214 | since(someObj).
215 | expect(3).toEqual(2);
216 | });
217 |
218 | it('containing #{actual} and #{expected} replacements', function() {
219 | someObj.toString = function() {
220 | return '#{expected} bla-bla-bla #{actual}';
221 | };
222 |
223 | expectMessageToEqual("2 bla-bla-bla 3").
224 | since(someObj).
225 | expect(3).toEqual(2);
226 | });
227 |
228 | });
229 |
230 | });
231 |
232 |
233 | describe('array', function() {
234 |
235 | var someArr = ['some', 'item'];
236 |
237 | it('without overridden toString method', function() {
238 | expectMessageToEqual('some,item').
239 | since(someArr).
240 | expect(3).toEqual(2);
241 | });
242 |
243 | describe('with overridden toString method', function() {
244 |
245 | it('without replacements', function() {
246 | someArr.toString = function() {
247 | return 'array bla-bla-bla';
248 | };
249 |
250 | expectMessageToEqual("array bla-bla-bla").
251 | since(someArr).
252 | expect(3).toEqual(2);
253 | });
254 |
255 | it('containing #{actual} and #{expected} replacements', function() {
256 | someArr.toString = function() {
257 | return '#{expected} bla-bla-bla #{actual}';
258 | };
259 |
260 | expectMessageToEqual("2 bla-bla-bla 3").
261 | since(someArr).
262 | expect(3).toEqual(2);
263 | });
264 |
265 | });
266 |
267 | });
268 |
269 | });
270 |
271 | });
272 |
273 | describe('custom failure messages for', function() {
274 |
275 | it('all assertions', function() {
276 | expectMessageToEqual("2 bla-bla-bla 3").
277 | since(function() {
278 | return this.expected + ' bla-bla-bla ' + this.actual;
279 | }).
280 | expect(3).toEqual(2);
281 |
282 | expectMessageToEqual("5 foo-bar-baz 4").
283 | since(function() {
284 | return this.expected + ' foo-bar-baz ' + this.actual;
285 | }).
286 | expect(4).toEqual(5);
287 | });
288 |
289 | it('some of the assertions', function() {
290 | expectMessageToEqual("Expected 3 to equal 2.").
291 | expect(3).toEqual(2);
292 |
293 | expectMessageToEqual("5 foo-bar-baz 4").
294 | since(function() {
295 | return this.expected + ' foo-bar-baz ' + this.actual;
296 | }).
297 | expect(4).toEqual(5);
298 | });
299 |
300 | it('inverse assertion', function() {
301 | expectMessageToEqual("2 bla-bla-bla 2").
302 | since("2 bla-bla-bla 2").
303 | expect(2).not.toEqual(2);
304 | });
305 |
306 | });
307 |
308 | });
309 |
310 | describe('should not generate', function() {
311 |
312 | describe('custom failure message when it is supplied', function() {
313 |
314 | describe('with', function() {
315 |
316 | it('null', function() {
317 | expectMessageToEqual("Expected 3 to equal 2.").
318 | since(null).
319 | expect(3).toEqual(2);
320 | });
321 |
322 | it('undefined', function() {
323 | expectMessageToEqual("Expected 3 to equal 2.").
324 | since(undefined).
325 | expect(3).toEqual(2);
326 | });
327 |
328 |
329 | describe('function returning', function() {
330 |
331 | it('null', function() {
332 | expectMessageToEqual("Expected 3 to equal 2.").
333 | since(function() {
334 | return null;
335 | }).
336 | expect(3).toEqual(2);
337 | });
338 |
339 | it('undefined', function() {
340 | expectMessageToEqual("Expected 3 to equal 2.").
341 | since(function() {
342 | return undefined;
343 | }).
344 | expect(3).toEqual(2);
345 | });
346 |
347 | });
348 |
349 | });
350 |
351 | });
352 |
353 | });
354 |
355 | });
356 |
357 | };
358 |
359 | if (isBrowserEnv) {
360 | test();
361 | } else {
362 | if (isCommonJS) {
363 | module.exports = test();
364 | }
365 | }
366 | })();
367 |
--------------------------------------------------------------------------------