├── .npmrc ├── .yarnrc ├── packages ├── jest-given │ ├── .npmignore │ ├── .core-version │ ├── tsconfig.build.json │ ├── jest.config.js │ ├── tsconfig.json │ ├── .all-contributorsrc │ ├── package.json │ ├── CHANGELOG.md │ ├── README.md │ └── spec │ │ └── jest-given.spec.ts ├── jasmine-given │ ├── .core-version │ ├── .npmignore │ ├── jasmine.json │ ├── tsconfig.build.json │ ├── tsconfig.json │ ├── .all-contributorsrc │ ├── package.json │ ├── CHANGELOG.md │ ├── README.md │ └── spec │ │ └── jasmine-given.spec.ts └── karma-jasmine-given │ ├── .npmignore │ ├── lib │ ├── karma-jasmine-given.spec.js │ └── karma-jasmine-given.js │ ├── .all-contributorsrc │ ├── package.json │ ├── karma.conf.js │ ├── CHANGELOG.md │ └── README.md ├── .eslintignore ├── for-readme └── test-angular.jpg ├── .prettierrc ├── .gitignore ├── .nycrc ├── lerna.json ├── .github ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ └── release.yml ├── .eslintrc.js ├── LICENSE ├── update-core-hash.js ├── .all-contributorsrc ├── package.json ├── shared └── given-core │ └── given-core.ts ├── CONTRIBUTING.md ├── CODE_OF_CONDUCT.md └── README.md /.npmrc: -------------------------------------------------------------------------------- 1 | save-exact = true -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | save-prefix "" -------------------------------------------------------------------------------- /packages/jest-given/.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | coverage 4 | .eslintrc.* -------------------------------------------------------------------------------- /packages/jest-given/.core-version: -------------------------------------------------------------------------------- 1 | 30d7377630e753cc9013b69da3d4514a3df7e867 -------------------------------------------------------------------------------- /packages/jasmine-given/.core-version: -------------------------------------------------------------------------------- 1 | 30d7377630e753cc9013b69da3d4514a3df7e867 -------------------------------------------------------------------------------- /packages/jasmine-given/.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | .nyc_output -------------------------------------------------------------------------------- /packages/karma-jasmine-given/.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | .nyc_output -------------------------------------------------------------------------------- /for-readme/test-angular.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hirezio/given/HEAD/for-readme/test-angular.jpg -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 90, 3 | "singleQuote": true, 4 | "useTabs": false, 5 | "tabWidth": 2, 6 | "semi": true, 7 | "bracketSpacing": true 8 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | temp-src 4 | coverage 5 | .nyc_output 6 | src/**/*.js* 7 | **/*.d.ts 8 | .vscode 9 | .cache 10 | TODO 11 | yarn-error.log 12 | lerna-debug.log -------------------------------------------------------------------------------- /packages/jasmine-given/jasmine.json: -------------------------------------------------------------------------------- 1 | { 2 | "spec_dir": "packages/jasmine-given/spec", 3 | "spec_files": [ 4 | "**/*[sS]pec.ts" 5 | ], 6 | "helpers": [], 7 | "stopSpecOnExpectationFailure": true, 8 | "stopOnSpecFailure": true, 9 | "random": true 10 | } 11 | -------------------------------------------------------------------------------- /packages/jasmine-given/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "ESNext", 5 | "rootDir": "./temp-src" 6 | }, 7 | "include": [ 8 | "temp-src" 9 | ], 10 | "exclude": ["**/*.spec.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/jest-given/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "./temp-src", 5 | "forceConsistentCasingInFileNames": true 6 | }, 7 | "include": ["temp-src"], 8 | "exclude": ["**/*.spec.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /.nycrc: -------------------------------------------------------------------------------- 1 | { 2 | "report-dir": "packages/jasmine-given/coverage", 3 | "temp-dir": "packages/jasmine-given/.nyc_output", 4 | "check-coverage": true, 5 | 6 | "include": [ 7 | "shared/given-core/given-core.ts" 8 | ], 9 | "branches": 100, 10 | "functions": 90, 11 | "lines": 90, 12 | "statements": 90 13 | } -------------------------------------------------------------------------------- /packages/karma-jasmine-given/lib/karma-jasmine-given.spec.js: -------------------------------------------------------------------------------- 1 | describe('Karma Jasmine Given', function(){ 2 | 3 | let num; 4 | 5 | Given(function () { 6 | num = 1; 7 | }); 8 | 9 | When(function(){ 10 | num++; 11 | }); 12 | 13 | Then(function(){ 14 | expect(num).toBe(2); 15 | }); 16 | 17 | }); -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": ["packages/*"], 3 | "npmClient": "yarn", 4 | "useWorkspaces": true, 5 | "version": "independent", 6 | "command": { 7 | "publish": { 8 | "conventionalCommits": true 9 | }, 10 | "version": { 11 | "conventionalCommits": true, 12 | "push": true, 13 | "gitTagVersion": true, 14 | "createRelease": "github", 15 | "allowBranch": "master", 16 | "message": "chore(release): publish new version" 17 | } 18 | }, 19 | "ignoreChanges": ["**/*.md", "**/*.spec.ts", "**/*.spec.js", "**/.all-contributorsrc"] 20 | } 21 | -------------------------------------------------------------------------------- /packages/jest-given/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | rootDir: '../../', 4 | roots: ['/shared/given-core', '/packages/jest-given/spec'], 5 | verbose: true, 6 | resetMocks: true, 7 | testEnvironment: 'node', 8 | collectCoverage: true, 9 | coverageDirectory: 'packages/jest-given/coverage', 10 | coverageThreshold: { 11 | global: { 12 | branches: 100, 13 | functions: 90, 14 | lines: 90, 15 | statements: 90, 16 | }, 17 | }, 18 | globals: { 19 | 'ts-jest': { 20 | tsconfig: '/packages/jest-given/tsconfig.json', 21 | }, 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /packages/jest-given/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es5", 5 | "moduleResolution": "node", 6 | "experimentalDecorators": true, 7 | "emitDecoratorMetadata": true, 8 | "declaration": true, // generate .d.ts files 9 | "declarationMap": true, 10 | "noImplicitAny": true, 11 | "noImplicitThis": false, 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "sourceMap": true, 15 | "downlevelIteration": true, 16 | "lib": ["es2015", "es2016", "dom"], 17 | "pretty": true, 18 | "strict": true, 19 | "baseUrl": ".", 20 | "outDir": "dist", 21 | "types": ["jest", "node"] 22 | }, 23 | "include": ["spec"] 24 | } 25 | -------------------------------------------------------------------------------- /packages/jasmine-given/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es5", 5 | "moduleResolution": "node", 6 | "experimentalDecorators": true, 7 | "emitDecoratorMetadata": true, 8 | "declaration": true, // generate .d.ts files 9 | "declarationMap": true, 10 | "noImplicitAny": true, 11 | "noImplicitThis": false, 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "sourceMap": true, 15 | "downlevelIteration": true, 16 | "lib": ["es2015", "es2016", "dom"], 17 | "pretty": true, 18 | "strict": true, 19 | "baseUrl": ".", 20 | "outDir": "dist", 21 | "types": ["jasmine", "node"] 22 | }, 23 | "include": ["spec"] 24 | } 25 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | plugins: ['@typescript-eslint'], 5 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], 6 | rules: { 7 | '@typescript-eslint/no-inferrable-types': 'off', 8 | '@typescript-eslint/no-explicit-any': 'off', 9 | '@typescript-eslint/no-this-alias': 'off', 10 | 'no-undef': 'off', 11 | }, 12 | overrides: [ 13 | { 14 | files: ['**/*.spec.ts'], 15 | rules: { 16 | '@typescript-eslint/no-explicit-any': 'off', 17 | '@typescript-eslint/no-unused-vars': 'off', 18 | '@typescript-eslint/ban-types': 'off', 19 | '@typescript-eslint/no-empty-function': 'off', 20 | }, 21 | }, 22 | ], 23 | }; 24 | -------------------------------------------------------------------------------- /packages/karma-jasmine-given/.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md", 4 | "../../README.md" 5 | ], 6 | "imageSize": 100, 7 | "commit": true, 8 | "commitConvention": "angular", 9 | "contributors": [ 10 | { 11 | "login": "shairez", 12 | "name": "Shai Reznik", 13 | "avatar_url": "https://avatars1.githubusercontent.com/u/1430726?v=4", 14 | "profile": "https://www.hirez.io/?utm_medium=Open_Source&utm_source=Github&utm_campaign=Lead_Generation&utm_content=karma-jasmine-given--all-contributors-profile-link", 15 | "contributions": [ 16 | "code", 17 | "doc", 18 | "ideas", 19 | "infra", 20 | "maintenance", 21 | "mentoring", 22 | "review", 23 | "test" 24 | ] 25 | } 26 | ], 27 | "contributorsPerLine": 7, 28 | "projectName": "given", 29 | "projectOwner": "hirezio", 30 | "repoType": "github", 31 | "repoHost": "https://github.com", 32 | "skipCi": true 33 | } 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior: 14 | 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | 28 | - OS: [e.g. iOS] 29 | - Browser [e.g. chrome, safari] 30 | - Version [e.g. 22] 31 | 32 | **Smartphone (please complete the following information):** 33 | 34 | - Device: [e.g. iPhone6] 35 | - OS: [e.g. iOS8.1] 36 | - Browser [e.g. stock browser, safari] 37 | - Version [e.g. 22] 38 | 39 | **Additional context** 40 | Add any other context about the problem here. 41 | -------------------------------------------------------------------------------- /packages/karma-jasmine-given/lib/karma-jasmine-given.js: -------------------------------------------------------------------------------- 1 | var createPattern = function (file) { 2 | return { 3 | pattern: file, 4 | included: true, 5 | served: true, 6 | watched: false, 7 | }; 8 | }; 9 | 10 | var initJasmineGiven = function (files) { 11 | jasmineGivenFile = createPattern(require.resolve('@hirez_io/jasmine-given')); 12 | 13 | // Find "karma-jasmine" last file (adapter.js) to make sure 14 | // "jasmine" is loaded before "jasmine-given" 15 | const karmaJasmineAdapterFileIndex = files.findIndex((file) => { 16 | return file.pattern.indexOf('adapter.js') !== -1; 17 | }); 18 | 19 | if (karmaJasmineAdapterFileIndex !== -1) { 20 | files.splice(karmaJasmineAdapterFileIndex + 1, 0, jasmineGivenFile); 21 | } else { 22 | files.unshift(jasmineGivenFile); 23 | } 24 | }; 25 | 26 | initJasmineGiven.$inject = ['config.files']; 27 | 28 | module.exports = { 29 | 'framework:@hirez_io/jasmine-given': ['factory', initJasmineGiven], 30 | 'framework:@hirez_io/karma-jasmine-given': ['factory', initJasmineGiven], 31 | }; 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Shai Reznik, HiRez.io 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. -------------------------------------------------------------------------------- /packages/jasmine-given/.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md", 4 | "../../README.md" 5 | ], 6 | "imageSize": 100, 7 | "commit": true, 8 | "commitConvention": "angular", 9 | "contributors": [ 10 | { 11 | "login": "shairez", 12 | "name": "Shai Reznik", 13 | "avatar_url": "https://avatars1.githubusercontent.com/u/1430726?v=4", 14 | "profile": "https://www.hirez.io/?utm_medium=Open_Source&utm_source=Github&utm_campaign=Lead_Generation&utm_content=given--all-contributors-profile-link", 15 | "contributions": [ 16 | "code", 17 | "doc", 18 | "ideas", 19 | "infra", 20 | "maintenance", 21 | "mentoring", 22 | "review", 23 | "test" 24 | ] 25 | }, 26 | { 27 | "login": "WynieCronje", 28 | "name": "WynieCronje", 29 | "avatar_url": "https://avatars.githubusercontent.com/u/4537265?v=4", 30 | "profile": "https://github.com/WynieCronje", 31 | "contributions": [ 32 | "code", 33 | "test", 34 | "maintenance" 35 | ] 36 | } 37 | ], 38 | "contributorsPerLine": 7, 39 | "projectName": "given", 40 | "projectOwner": "hirezio", 41 | "repoType": "github", 42 | "repoHost": "https://github.com", 43 | "skipCi": true 44 | } 45 | -------------------------------------------------------------------------------- /packages/jest-given/.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md", 4 | "../../README.md" 5 | ], 6 | "imageSize": 100, 7 | "commit": true, 8 | "commitConvention": "angular", 9 | "contributors": [ 10 | { 11 | "login": "shairez", 12 | "name": "Shai Reznik", 13 | "avatar_url": "https://avatars1.githubusercontent.com/u/1430726?v=4", 14 | "profile": "https://www.hirez.io/?utm_medium=Open_Source&utm_source=Github&utm_campaign=Lead_Generation&utm_content=jest-given--all-contributors-profile-link", 15 | "contributions": [ 16 | "code", 17 | "doc", 18 | "ideas", 19 | "infra", 20 | "maintenance", 21 | "mentoring", 22 | "review", 23 | "test" 24 | ] 25 | }, 26 | { 27 | "login": "WynieCronje", 28 | "name": "WynieCronje", 29 | "avatar_url": "https://avatars.githubusercontent.com/u/4537265?v=4", 30 | "profile": "https://github.com/WynieCronje", 31 | "contributions": [ 32 | "code", 33 | "test", 34 | "maintenance" 35 | ] 36 | } 37 | ], 38 | "contributorsPerLine": 7, 39 | "projectName": "given", 40 | "projectOwner": "hirezio", 41 | "repoType": "github", 42 | "repoHost": "https://github.com", 43 | "skipCi": true 44 | } 45 | -------------------------------------------------------------------------------- /packages/karma-jasmine-given/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hirez_io/karma-jasmine-given", 3 | "version": "1.1.2", 4 | "publishConfig": { 5 | "access": "public", 6 | "registry": "https://registry.npmjs.com" 7 | }, 8 | "author": { 9 | "name": "Shai Reznik", 10 | "company": "HiRez.io" 11 | }, 12 | "description": "A karma plugin for loading @hirez_io/jasmine-given", 13 | "keywords": [ 14 | "jasmine", 15 | "jasmine-given", 16 | "jasmine-karma", 17 | "karma", 18 | "gwt", 19 | "Given When Then", 20 | "Microtests", 21 | "Testing", 22 | "Unit tests", 23 | "JavasScript Unit Tests", 24 | "TypeScript Unit Tests", 25 | "hirez.io" 26 | ], 27 | "homepage": "https://github.com/hirezio/given/tree/master/packages/karma-jasmine-given", 28 | "repository": { 29 | "type": "git", 30 | "url": "https://github.com/hirezio/given", 31 | "directory": "packages/karma-jasmine-given" 32 | }, 33 | "license": "MIT", 34 | "main": "lib/karma-jasmine-given.js", 35 | "scripts": { 36 | "build": "echo build is not needed for the karma plugin", 37 | "test": "karma start" 38 | }, 39 | "bugs": { 40 | "url": "https://github.com/shairez/given/issues" 41 | }, 42 | "devDependencies": { 43 | "karma": "6.4.0", 44 | "karma-chrome-launcher": "3.1.1", 45 | "karma-jasmine": "5.1.0" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /update-core-hash.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | 3 | const fs = require('fs').promises; 4 | const execa = require('execa'); 5 | 6 | (async () => { 7 | try { 8 | const coreFileName = 'shared/given-core/given-core.ts'; 9 | const jestCacheOfHashFileName = 'packages/jest-given/.core-version'; 10 | const jasmineCacheOfHashFileName = 'packages/jasmine-given/.core-version'; 11 | 12 | const {stdout} = await execa('git', ['hash-object', coreFileName]); 13 | const latestCoreHash = stdout; 14 | 15 | const jestCachedHash = await fs.readFile(jestCacheOfHashFileName, 'utf8'); 16 | const jasmineCachedHash = await fs.readFile(jasmineCacheOfHashFileName, 'utf8'); 17 | 18 | if (jestCachedHash === latestCoreHash && jasmineCachedHash === latestCoreHash) { 19 | console.log('No changes in given-core'); 20 | return; 21 | } 22 | 23 | await fs.writeFile(jestCacheOfHashFileName, latestCoreHash); 24 | await fs.writeFile(jasmineCacheOfHashFileName, latestCoreHash); 25 | 26 | console.log( 27 | 'Updated given-core hash to help lerna know that it needs to bump versions' 28 | ); 29 | 30 | // await execa('git', ['add', jestCacheOfHashFileName, jasmineCacheOfHashFileName]); 31 | 32 | // const { stdout } = await execa('git', ['commit', '--amend', '--no-edit']); 33 | console.log(stdout); 34 | } catch (error) { 35 | console.error(error); 36 | } 37 | })(); 38 | -------------------------------------------------------------------------------- /packages/jest-given/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hirez_io/jest-given", 3 | "version": "1.1.3", 4 | "publishConfig": { 5 | "access": "public", 6 | "registry": "https://registry.npmjs.com" 7 | }, 8 | "author": { 9 | "name": "Shai Reznik", 10 | "company": "HiRez.io" 11 | }, 12 | "description": "A jest addon that helps you clean up your microtests by breaking them into a Given / When / Then structure.", 13 | "keywords": [ 14 | "jest", 15 | "jest-given", 16 | "gwt", 17 | "Given When Then", 18 | "Microtests", 19 | "Testing", 20 | "Unit tests", 21 | "JavasScript Unit Tests", 22 | "TypeScript Unit Tests", 23 | "hirez.io" 24 | ], 25 | "homepage": "https://github.com/hirezio/given/tree/master/packages/jest-given", 26 | "repository": { 27 | "type": "git", 28 | "url": "https://github.com/hirezio/given", 29 | "directory": "packages/jest-given" 30 | }, 31 | "license": "MIT", 32 | "main": "dist/jest-given.js", 33 | "types": "dist/jest-given.d.ts", 34 | "scripts": { 35 | "clean": "rimraf dist", 36 | "clean:temp-src": "rimraf temp-src", 37 | "copy:shared-source": "cpy ../../shared/given-core/given-core.ts ./temp-src/ --rename=jest-given.ts", 38 | "compile": "tsc -p tsconfig.build.json", 39 | "build": "run-s clean copy:shared-source compile", 40 | "test": "echo \n*** Run tests from the root folder\n" 41 | }, 42 | "peerDependencies": { 43 | "jest": "< 30.x" 44 | }, 45 | "devDependencies": { 46 | "@types/jest": "29.5.1", 47 | "cpy-cli": "^3.1.1", 48 | "jest": "29.5.0", 49 | "microbundle": "^0.15.1", 50 | "ts-jest": "29.1.0" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": true, 7 | "commitConvention": "angular", 8 | "contributors": [ 9 | { 10 | "login": "shairez", 11 | "name": "Shai Reznik", 12 | "avatar_url": "https://avatars1.githubusercontent.com/u/1430726?v=4", 13 | "profile": "https://www.hirez.io/?utm_medium=Open_Source&utm_source=Github&utm_campaign=Lead_Generation&utm_content=given--all-contributors-profile-link", 14 | "contributions": [ 15 | "code", 16 | "doc", 17 | "ideas", 18 | "infra", 19 | "maintenance", 20 | "mentoring", 21 | "review", 22 | "test" 23 | ] 24 | }, 25 | { 26 | "login": "WynieCronje", 27 | "name": "WynieCronje", 28 | "avatar_url": "https://avatars.githubusercontent.com/u/4537265?v=4", 29 | "profile": "https://github.com/WynieCronje", 30 | "contributions": [ 31 | "code", 32 | "test", 33 | "maintenance" 34 | ] 35 | }, 36 | { 37 | "login": "Yianen", 38 | "name": "Yianen", 39 | "avatar_url": "https://avatars.githubusercontent.com/u/29684111?v=4", 40 | "profile": "https://github.com/Yianen", 41 | "contributions": [ 42 | "code", 43 | "test", 44 | "maintenance" 45 | ] 46 | }, 47 | { 48 | "login": "fouchekeagan", 49 | "name": "Keagan Fouché", 50 | "avatar_url": "https://avatars.githubusercontent.com/u/72212540?v=4", 51 | "profile": "https://github.com/fouchekeagan", 52 | "contributions": [ 53 | "code", 54 | "maintenance" 55 | ] 56 | } 57 | ], 58 | "contributorsPerLine": 7, 59 | "projectName": "given", 60 | "projectOwner": "hirezio", 61 | "repoType": "github", 62 | "repoHost": "https://github.com", 63 | "skipCi": true, 64 | "commitType": "docs" 65 | } 66 | -------------------------------------------------------------------------------- /packages/karma-jasmine-given/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Tue Aug 11 2020 14:21:54 GMT+0300 (Israel Daylight Time) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | plugins: [ 8 | require('karma-jasmine'), 9 | require('@hirez_io/karma-jasmine-given'), 10 | require('karma-chrome-launcher') 11 | ], 12 | 13 | // base path that will be used to resolve all patterns (eg. files, exclude) 14 | basePath: '', 15 | 16 | 17 | // frameworks to use 18 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 19 | frameworks: ['@hirez_io/jasmine-given', 'jasmine'], 20 | 21 | // list of files / patterns to load in the browser 22 | files: [ 23 | './lib/karma-jasmine-given.spec.js' 24 | ], 25 | 26 | // test results reporter to use 27 | // possible values: 'dots', 'progress' 28 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 29 | reporters: ['progress'], 30 | 31 | 32 | // web server port 33 | port: 9876, 34 | 35 | 36 | // enable / disable colors in the output (reporters and logs) 37 | colors: true, 38 | 39 | 40 | // level of logging 41 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 42 | logLevel: config.LOG_INFO, 43 | 44 | 45 | // enable / disable watching file and executing tests whenever any file changes 46 | autoWatch: false, 47 | 48 | 49 | // start these browsers 50 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 51 | browsers: ['ChromeHeadless'], 52 | // browsers: ['Chrome'], 53 | 54 | 55 | // Continuous Integration mode 56 | // if true, Karma captures browsers, runs the tests and exits 57 | singleRun: true, 58 | 59 | // Concurrency level 60 | // how many browser should be started simultaneous 61 | concurrency: Infinity 62 | }) 63 | } 64 | -------------------------------------------------------------------------------- /packages/jasmine-given/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hirez_io/jasmine-given", 3 | "version": "1.1.2", 4 | "publishConfig": { 5 | "access": "public", 6 | "registry": "https://registry.npmjs.com" 7 | }, 8 | "author": { 9 | "name": "Shai Reznik", 10 | "company": "HiRez.io" 11 | }, 12 | "description": "A jasmine addon that helps you clean up your microtests by breaking them into a Given / When / Then structure.", 13 | "keywords": [ 14 | "jasmine", 15 | "jasmine-given", 16 | "gwt", 17 | "Given When Then", 18 | "Microtests", 19 | "Testing", 20 | "Unit tests", 21 | "JavasScript Unit Tests", 22 | "TypeScript Unit Tests", 23 | "hirez.io" 24 | ], 25 | "homepage": "https://github.com/hirezio/given/tree/master/packages/jasmine-given", 26 | "repository": { 27 | "type": "git", 28 | "url": "https://github.com/hirezio/given", 29 | "directory": "packages/jasmine-given" 30 | }, 31 | "license": "MIT", 32 | "source": "temp-src/jasmine-given.ts", 33 | "main": "dist/jasmine-given.js", 34 | "types": "dist/jasmine-given.d.ts", 35 | "scripts": { 36 | "clean": "rimraf dist", 37 | "clean:temp-src": "rimraf temp-src", 38 | "copy:shared-source": "cpy ../../shared/given-core/given-core.ts ./temp-src/ --rename=jasmine-given.ts", 39 | "compile": "microbundle -f iife --tsconfig tsconfig.build.json --compress false", 40 | "build": "run-s clean copy:shared-source compile clean:temp-src", 41 | "test": "echo \n*** Run tests from the root folder\n" 42 | }, 43 | "dependencies": { 44 | "@hirez_io/karma-jasmine-given": "^1.1.2" 45 | }, 46 | "peerDependencies": { 47 | "jasmine-core": "< 5.x" 48 | }, 49 | "devDependencies": { 50 | "@types/jasmine": "4.0.3", 51 | "cpy-cli": "^3.1.1", 52 | "jasmine": "4.3.0", 53 | "microbundle": "^0.15.0", 54 | "nodemon": "2.0.19", 55 | "nyc": "15.1.0", 56 | "source-map-support": "^0.5.21", 57 | "tsconfig-paths": "4.0.0" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "given", 3 | "version": "0.0.0", 4 | "author": { 5 | "name": "Shai Reznik", 6 | "company": "HiRez.io" 7 | }, 8 | "license": "MIT", 9 | "private": true, 10 | "scripts": { 11 | "commit": "git-cz", 12 | "build": "lerna run build", 13 | "format:fix": "pretty-quick --staged", 14 | "lerna:publish": "lerna publish from-git --yes", 15 | "lerna:version": "lerna version", 16 | "lerna:version:ci": "lerna version --yes", 17 | "lint": "eslint . --ext .js,.ts", 18 | "lint:commitmsg": "commitlint -E HUSKY_GIT_PARAMS", 19 | "test": "run-s test:jasmine:coverage test:jest", 20 | "test:full": "run-s lint test", 21 | "test:jasmine": "ts-node --project packages/jasmine-given/tsconfig.json -r tsconfig-paths/register node_modules/jasmine/bin/jasmine.js JASMINE_CONFIG_PATH=packages/jasmine-given/jasmine.json", 22 | "test:jasmine:coverage": "nyc -r lcov --r text-summary -e .ts -x \"**/*.spec.ts\" yarn test:jasmine", 23 | "test:jasmine:watch": "nodemon --ext ts --watch \"shared/given-core/**/*.ts\" --watch \"packages/jasmine-given/**/*.ts\" --exec \"yarn test:jasmine:coverage\"", 24 | "test:jest": "jest -c packages/jest-given/jest.config.js", 25 | "test:jest:watch": "jest -c packages/jest-given/jest.config.js --watchAll", 26 | "update-core-hash": "node update-core-hash" 27 | }, 28 | "workspaces": [ 29 | "packages/*" 30 | ], 31 | "config": { 32 | "commitizen": { 33 | "path": "./node_modules/cz-conventional-changelog" 34 | } 35 | }, 36 | "husky": { 37 | "hooks": { 38 | "pre-commit": "yarn format:fix", 39 | "commit-msg": "yarn lint:commitmsg", 40 | "post-commit": "yarn update-core-hash" 41 | } 42 | }, 43 | "commitlint": { 44 | "extends": [ 45 | "@commitlint/config-conventional" 46 | ] 47 | }, 48 | "devDependencies": { 49 | "@commitlint/cli": "17.0.3", 50 | "@commitlint/config-conventional": "17.0.3", 51 | "@types/node": "18.6.1", 52 | "@typescript-eslint/eslint-plugin": "5.30.7", 53 | "@typescript-eslint/parser": "5.30.7", 54 | "commitizen": "4.2.5", 55 | "cz-conventional-changelog": "3.3.0", 56 | "eslint": "8.20.0", 57 | "eslint-config-prettier": "8.5.0", 58 | "execa": "4.0.3", 59 | "husky": "4.2.5", 60 | "lerna": "^3.22.1", 61 | "npm-run-all": "^4.1.5", 62 | "prettier": "2.7.1", 63 | "pretty-quick": "3.1.3", 64 | "rimraf": "^3.0.2", 65 | "ts-node": "10.9.1", 66 | "typescript": "4.7.4" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /packages/karma-jasmine-given/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [1.1.3](https://github.com/hirezio/given/compare/@hirez_io/karma-jasmine-given@1.1.2...@hirez_io/karma-jasmine-given@1.1.3) (2023-06-03) 7 | 8 | **Note:** Version bump only for package @hirez_io/karma-jasmine-given 9 | 10 | 11 | 12 | 13 | 14 | ## [1.1.2](https://github.com/hirezio/given/compare/@hirez_io/karma-jasmine-given@1.1.1...@hirez_io/karma-jasmine-given@1.1.2) (2022-07-25) 15 | 16 | 17 | ### Bug Fixes 18 | 19 | * **global:** upgrade jest version to 28 ([05b447f](https://github.com/hirezio/given/commit/05b447fcaf3cddfc346253f31e2630100488095c)), closes [#14](https://github.com/hirezio/given/issues/14) 20 | 21 | 22 | 23 | 24 | 25 | ## [1.1.1](https://github.com/hirezio/given/compare/@hirez_io/karma-jasmine-given@1.1.0...@hirez_io/karma-jasmine-given@1.1.1) (2022-03-13) 26 | 27 | **Note:** Version bump only for package @hirez_io/karma-jasmine-given 28 | 29 | 30 | 31 | 32 | 33 | # [1.1.0](https://github.com/hirezio/given/compare/@hirez_io/karma-jasmine-given@1.0.3...@hirez_io/karma-jasmine-given@1.1.0) (2021-01-22) 34 | 35 | 36 | ### Features 37 | 38 | * **karma-jasmine-given:** add `[@hirez](https://github.com/hirez)_io/karma-jasmine-given` as a karma framework ([5414855](https://github.com/hirezio/given/commit/5414855e73281bb965b0a6cf993066bf28888017)), closes [#1](https://github.com/hirezio/given/issues/1) [#3](https://github.com/hirezio/given/issues/3) 39 | 40 | 41 | 42 | 43 | 44 | ## [1.0.3](https://github.com/hirezio/given/compare/@hirez_io/karma-jasmine-given@1.0.2...@hirez_io/karma-jasmine-given@1.0.3) (2020-08-25) 45 | 46 | **Note:** Version bump only for package @hirez_io/karma-jasmine-given 47 | 48 | 49 | 50 | 51 | 52 | ## [1.0.2](https://github.com/hirezio/given/compare/@hirez_io/karma-jasmine-given@1.0.1...@hirez_io/karma-jasmine-given@1.0.2) (2020-08-25) 53 | 54 | 55 | ### Bug Fixes 56 | 57 | * **global:** fix npmignore files and tsconfig.json ([b29a1ee](https://github.com/hirezio/given/commit/b29a1eeaa5739f93f4d5120477f7bcd23a60a121)) 58 | 59 | 60 | 61 | 62 | 63 | ## [1.0.1](https://github.com/hirezio/given/compare/@hirez_io/karma-jasmine-given@1.0.0...@hirez_io/karma-jasmine-given@1.0.1) (2020-08-18) 64 | 65 | **Note:** Version bump only for package @hirez_io/karma-jasmine-given 66 | 67 | 68 | 69 | 70 | 71 | # 1.0.0 (2020-08-18) 72 | 73 | ### Features 74 | 75 | - **global:** initial commit ([797e2e3](https://github.com/hirezio/given/commit/797e2e373e23bfeeeaa669921aa7c047f6ee8d9c)) 76 | 77 | # 1.0.0 (2020-08-18) 78 | 79 | ### Features 80 | 81 | - **global:** initial commit ([da99fe3](https://github.com/hirezio/given/commit/da99fe30c4021cd6534692d33555b2165970351e)) 82 | 83 | # 1.0.0 (2020-08-15) 84 | 85 | ### Features 86 | 87 | - **global:** initial commit ([ac8863e](https://github.com/hirezio/given/commit/ac8863e91f8fc10f7437a9afa5a05c5dfd19fd74)) 88 | 89 | ### BREAKING CHANGES 90 | 91 | - **global:** initial commit 92 | -------------------------------------------------------------------------------- /packages/jest-given/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [1.1.4](https://github.com/hirezio/given/compare/@hirez_io/jest-given@1.1.3...@hirez_io/jest-given@1.1.4) (2023-06-03) 7 | 8 | **Note:** Version bump only for package @hirez_io/jest-given 9 | 10 | 11 | 12 | 13 | 14 | ## [1.1.3](https://github.com/hirezio/given/compare/@hirez_io/jest-given@1.1.1...@hirez_io/jest-given@1.1.3) (2023-06-03) 15 | 16 | 17 | ### Bug Fixes 18 | 19 | * **jest-given:** upgrade jest version to 29 ([d3d02b8](https://github.com/hirezio/given/commit/d3d02b8fbdd522bce2e41490dccfd27ebabe21df)) 20 | 21 | 22 | 23 | 24 | 25 | ## [1.1.1](https://github.com/hirezio/given/compare/@hirez_io/jest-given@1.1.0...@hirez_io/jest-given@1.1.1) (2022-07-25) 26 | 27 | 28 | ### Bug Fixes 29 | 30 | * **global:** upgrade jest version to 28 ([05b447f](https://github.com/hirezio/given/commit/05b447fcaf3cddfc346253f31e2630100488095c)), closes [#14](https://github.com/hirezio/given/issues/14) 31 | 32 | 33 | 34 | 35 | 36 | # [1.1.0](https://github.com/hirezio/given/compare/@hirez_io/jest-given@1.0.4...@hirez_io/jest-given@1.1.0) (2022-03-25) 37 | 38 | 39 | ### Features 40 | 41 | * **given-core:** show original error details in new context error ([bb92e36](https://github.com/hirezio/given/commit/bb92e365027f4f6f70583abc3b598795d6e491ba)), closes [#6](https://github.com/hirezio/given/issues/6) 42 | 43 | 44 | 45 | 46 | 47 | ## [1.0.4](https://github.com/hirezio/given/compare/@hirez_io/jest-given@1.0.3...@hirez_io/jest-given@1.0.4) (2022-03-13) 48 | 49 | **Note:** Version bump only for package @hirez_io/jest-given 50 | 51 | 52 | 53 | 54 | 55 | ## [1.0.3](https://github.com/hirezio/given/compare/@hirez_io/jest-given@1.0.2...@hirez_io/jest-given@1.0.3) (2020-08-25) 56 | 57 | **Note:** Version bump only for package @hirez_io/jest-given 58 | 59 | 60 | 61 | 62 | 63 | ## [1.0.2](https://github.com/hirezio/given/compare/@hirez_io/jest-given@1.0.1...@hirez_io/jest-given@1.0.2) (2020-08-25) 64 | 65 | 66 | ### Bug Fixes 67 | 68 | * **global:** fix npmignore files and tsconfig.json ([b29a1ee](https://github.com/hirezio/given/commit/b29a1eeaa5739f93f4d5120477f7bcd23a60a121)) 69 | 70 | 71 | 72 | 73 | 74 | ## [1.0.1](https://github.com/hirezio/given/compare/@hirez_io/jest-given@1.0.0...@hirez_io/jest-given@1.0.1) (2020-08-18) 75 | 76 | **Note:** Version bump only for package @hirez_io/jest-given 77 | 78 | 79 | 80 | 81 | 82 | # 1.0.0 (2020-08-18) 83 | 84 | ### Features 85 | 86 | - **global:** initial commit ([797e2e3](https://github.com/hirezio/given/commit/797e2e373e23bfeeeaa669921aa7c047f6ee8d9c)) 87 | 88 | # 1.0.0 (2020-08-18) 89 | 90 | ### Features 91 | 92 | - **global:** initial commit ([da99fe3](https://github.com/hirezio/given/commit/da99fe30c4021cd6534692d33555b2165970351e)) 93 | 94 | # 1.0.0 (2020-08-15) 95 | 96 | ### Features 97 | 98 | - **global:** initial commit ([ac8863e](https://github.com/hirezio/given/commit/ac8863e91f8fc10f7437a9afa5a05c5dfd19fd74)) 99 | 100 | ### BREAKING CHANGES 101 | 102 | - **global:** initial commit 103 | -------------------------------------------------------------------------------- /packages/jasmine-given/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [1.1.3](https://github.com/hirezio/given/compare/@hirez_io/jasmine-given@1.1.2...@hirez_io/jasmine-given@1.1.3) (2023-06-03) 7 | 8 | **Note:** Version bump only for package @hirez_io/jasmine-given 9 | 10 | 11 | 12 | 13 | 14 | ## [1.1.2](https://github.com/hirezio/given/compare/@hirez_io/jasmine-given@1.1.1...@hirez_io/jasmine-given@1.1.2) (2023-06-03) 15 | 16 | 17 | ### Bug Fixes 18 | 19 | * **jest-given:** upgrade jest version to 29 ([d3d02b8](https://github.com/hirezio/given/commit/d3d02b8fbdd522bce2e41490dccfd27ebabe21df)) 20 | 21 | 22 | 23 | 24 | 25 | ## [1.1.1](https://github.com/hirezio/given/compare/@hirez_io/jasmine-given@1.1.0...@hirez_io/jasmine-given@1.1.1) (2022-07-25) 26 | 27 | 28 | ### Bug Fixes 29 | 30 | * **global:** upgrade jest version to 28 ([05b447f](https://github.com/hirezio/given/commit/05b447fcaf3cddfc346253f31e2630100488095c)), closes [#14](https://github.com/hirezio/given/issues/14) 31 | 32 | 33 | 34 | 35 | 36 | # [1.1.0](https://github.com/hirezio/given/compare/@hirez_io/jasmine-given@1.0.7...@hirez_io/jasmine-given@1.1.0) (2022-03-25) 37 | 38 | 39 | ### Features 40 | 41 | * **given-core:** show original error details in new context error ([bb92e36](https://github.com/hirezio/given/commit/bb92e365027f4f6f70583abc3b598795d6e491ba)), closes [#6](https://github.com/hirezio/given/issues/6) 42 | 43 | 44 | 45 | 46 | 47 | ## [1.0.7](https://github.com/hirezio/given/compare/@hirez_io/jasmine-given@1.0.6...@hirez_io/jasmine-given@1.0.7) (2022-03-13) 48 | 49 | **Note:** Version bump only for package @hirez_io/jasmine-given 50 | 51 | 52 | 53 | 54 | 55 | ## [1.0.6](https://github.com/hirezio/given/compare/@hirez_io/jasmine-given@1.0.5...@hirez_io/jasmine-given@1.0.6) (2022-03-11) 56 | 57 | **Note:** Version bump only for package @hirez_io/jasmine-given 58 | 59 | 60 | 61 | 62 | 63 | ## [1.0.5](https://github.com/hirezio/given/compare/@hirez_io/jasmine-given@1.0.4...@hirez_io/jasmine-given@1.0.5) (2021-01-22) 64 | 65 | **Note:** Version bump only for package @hirez_io/jasmine-given 66 | 67 | 68 | 69 | 70 | 71 | ## [1.0.4](https://github.com/hirezio/given/compare/@hirez_io/jasmine-given@1.0.3...@hirez_io/jasmine-given@1.0.4) (2020-08-30) 72 | 73 | 74 | ### Bug Fixes 75 | 76 | * **jasmine-given:** changed peer dep from jasmine to jasmine-core ([5b952e5](https://github.com/hirezio/given/commit/5b952e5cd8c3b86a7708bceb5cf2e90e020d3896)) 77 | 78 | 79 | 80 | 81 | 82 | ## [1.0.3](https://github.com/hirezio/given/compare/@hirez_io/jasmine-given@1.0.2...@hirez_io/jasmine-given@1.0.3) (2020-08-25) 83 | 84 | **Note:** Version bump only for package @hirez_io/jasmine-given 85 | 86 | 87 | 88 | 89 | 90 | ## [1.0.2](https://github.com/hirezio/given/compare/@hirez_io/jasmine-given@1.0.1...@hirez_io/jasmine-given@1.0.2) (2020-08-25) 91 | 92 | 93 | ### Bug Fixes 94 | 95 | * **global:** fix npmignore files and tsconfig.json ([b29a1ee](https://github.com/hirezio/given/commit/b29a1eeaa5739f93f4d5120477f7bcd23a60a121)) 96 | 97 | 98 | 99 | 100 | 101 | ## [1.0.1](https://github.com/hirezio/given/compare/@hirez_io/jasmine-given@1.0.0...@hirez_io/jasmine-given@1.0.1) (2020-08-18) 102 | 103 | **Note:** Version bump only for package @hirez_io/jasmine-given 104 | 105 | 106 | 107 | 108 | 109 | # 1.0.0 (2020-08-18) 110 | 111 | ### Features 112 | 113 | - **global:** initial commit ([797e2e3](https://github.com/hirezio/given/commit/797e2e373e23bfeeeaa669921aa7c047f6ee8d9c)) 114 | 115 | # 1.0.0 (2020-08-18) 116 | 117 | ### Features 118 | 119 | - **global:** initial commit ([da99fe3](https://github.com/hirezio/given/commit/da99fe30c4021cd6534692d33555b2165970351e)) 120 | 121 | # 1.0.0 (2020-08-15) 122 | 123 | ### Features 124 | 125 | - **global:** initial commit ([ac8863e](https://github.com/hirezio/given/commit/ac8863e91f8fc10f7437a9afa5a05c5dfd19fd74)) 126 | 127 | ### BREAKING CHANGES 128 | 129 | - **global:** initial commit 130 | -------------------------------------------------------------------------------- /shared/given-core/given-core.ts: -------------------------------------------------------------------------------- 1 | export const NO_SPEC_FUNCTION_ERROR = 2 | 'You must provide a function as the second argument to Then("some label", () => {} )'; 3 | 4 | export const CONTEXT_FOR_GWT_ERROR = 'An error was thrown in'; 5 | 6 | export const NO_STACK_ERROR = `Unfortunately, this error was thrown as a string, 7 | so no *real* stack trace for you :(`; 8 | 9 | export interface DoneFn { 10 | (...args: Error[]): void; 11 | fail: (...args: Error[]) => void; 12 | } 13 | 14 | interface TestCallback { 15 | (done: DoneFn): any; 16 | } 17 | 18 | declare global { 19 | function Given(fn: TestCallback): void; 20 | function When(fn: TestCallback): void; 21 | function Then(label: string, fn: TestCallback): void; 22 | function Then(fn: TestCallback): void; 23 | } 24 | 25 | const root = (0, eval)('this'); 26 | const whenFnsQueue: any[] = []; 27 | 28 | let currentUserContext: any = null; 29 | 30 | beforeEach(function () { 31 | currentUserContext = this; 32 | }); 33 | 34 | root.Given = function Given(givenSetupFn: any) { 35 | async function wrappedFn() { 36 | try { 37 | return await promisify(givenSetupFn); 38 | } catch (error: any) { 39 | throwErrorWithContext('Given', error); 40 | } 41 | } 42 | 43 | beforeEach(wrappedFn); 44 | }; 45 | 46 | root.When = function When(whenSetupFn: any) { 47 | beforeEach(function addWhenToQueue() { 48 | whenFnsQueue.push(whenSetupFn); 49 | }); 50 | 51 | afterEach(function cleanWhenQueue() { 52 | whenFnsQueue.pop(); 53 | }); 54 | }; 55 | 56 | root.Then = function Then(specFnOrLabel: TestCallback | string, specFn?: TestCallback) { 57 | const [label, actualSpecFunction] = getLabelAndFunction(specFnOrLabel, specFn); 58 | 59 | it(label, async function itCallbackInsideOfThen() { 60 | const fnQueue = [...whenFnsQueue, actualSpecFunction]; 61 | const fnsLength = fnQueue.length; 62 | 63 | for (const [fnIndex, fn] of fnQueue.entries()) { 64 | const originFunctionName = fnIndex === fnsLength - 1 ? 'Then' : 'When'; 65 | 66 | try { 67 | await promisify(fn); 68 | } catch (error: any) { 69 | throwErrorWithContext(originFunctionName, error); 70 | } 71 | } 72 | }); 73 | }; 74 | 75 | function getLabelAndFunction( 76 | specFnOrLabel: string | TestCallback, 77 | specFn?: TestCallback 78 | ): [string, TestCallback] { 79 | let label: string = ''; 80 | let actualSpecFunction: TestCallback; 81 | if (typeof specFnOrLabel === 'string') { 82 | label = '\n -> Then ' + specFnOrLabel; 83 | if (!specFn) { 84 | throw new Error(NO_SPEC_FUNCTION_ERROR); 85 | } 86 | actualSpecFunction = specFn; 87 | } else { 88 | actualSpecFunction = specFnOrLabel; 89 | } 90 | return [label, actualSpecFunction]; 91 | } 92 | 93 | async function promisify(fn: TestCallback): Promise { 94 | if (doesFunctionHaveParams(fn)) { 95 | return new Promise((resolve, reject) => { 96 | function next(err: Error) { 97 | if (err) { 98 | reject(err); 99 | return; 100 | } 101 | resolve(undefined); 102 | } 103 | next.fail = function nextFail(err: Error) { 104 | reject(err); 105 | }; 106 | 107 | fn.call(currentUserContext, next); 108 | }); 109 | } 110 | return await (fn as () => any).call(currentUserContext); 111 | } 112 | 113 | function throwErrorWithContext( 114 | originFunctionName: string, 115 | originalError: Error | string 116 | ) { 117 | const messagePrefix = `${CONTEXT_FOR_GWT_ERROR} ${originFunctionName}():`; 118 | 119 | if (typeof originalError === 'string') { 120 | throw new Error(`${messagePrefix}\n${originalError}\n${NO_STACK_ERROR}`); 121 | } 122 | 123 | const errorMessage = `${originalError.name || 'Error'}: ${originalError.message}`; 124 | const newError = new Error(`${messagePrefix}\n${errorMessage}`); 125 | 126 | newError.stack = `${messagePrefix}\n${originalError.stack}`; 127 | 128 | throw newError; 129 | } 130 | 131 | function doesFunctionHaveParams(fn: (...args: any[]) => any) { 132 | return fn.length > 0; 133 | } 134 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | branches: 5 | - master 6 | - staging 7 | pull_request: 8 | jobs: 9 | build: 10 | name: Build and test on node ${{ matrix.node }} 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | node: ['14', '16'] 15 | env: 16 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 17 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 18 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 19 | steps: 20 | - name: Checkout Repo 21 | uses: actions/checkout@v2 22 | with: 23 | fetch-depth: '0' 24 | - name: Setup Node 25 | uses: actions/setup-node@v2-beta 26 | with: 27 | node-version: ${{ matrix.node }} 28 | registry-url: 'https://registry.npmjs.org' 29 | - name: Get yarn cache dir 30 | id: yarn-cache-dir-path 31 | run: echo "::set-output name=dir::$(yarn cache dir)" 32 | 33 | - name: Cache Dependencies 34 | uses: actions/cache@v2 35 | id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) 36 | with: 37 | path: | 38 | ${{ steps.yarn-cache-dir-path.outputs.dir }} 39 | node_modules 40 | */*/node_modules 41 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 42 | restore-keys: | 43 | ${{ runner.os }}-yarn- 44 | 45 | - name: Install dependencies 46 | run: yarn install --frozen-lockfile 47 | 48 | - name: Build 49 | run: yarn build 50 | 51 | - name: Run Lint and Tests 52 | run: yarn test:full 53 | release: 54 | name: Release 55 | if: github.event_name == 'push' && github.ref == 'refs/heads/master' 56 | needs: build 57 | runs-on: ubuntu-latest 58 | env: 59 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 60 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 61 | steps: 62 | - name: Checkout Repo 63 | uses: actions/checkout@v2 64 | with: 65 | fetch-depth: '0' 66 | 67 | - name: Setup Node 68 | uses: actions/setup-node@v2-beta 69 | with: 70 | node-version: '16' 71 | registry-url: 'https://registry.npmjs.org' 72 | scope: '@hirez_io' 73 | 74 | - name: Get yarn cache dir 75 | id: yarn-cache-dir-path 76 | run: echo "::set-output name=dir::$(yarn cache dir)" 77 | 78 | - name: Cache Dependencies 79 | uses: actions/cache@v2 80 | id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) 81 | with: 82 | path: | 83 | ${{ steps.yarn-cache-dir-path.outputs.dir }} 84 | node_modules 85 | */*/node_modules 86 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 87 | restore-keys: | 88 | ${{ runner.os }}-yarn- 89 | 90 | - name: Install dependencies 91 | run: yarn install --frozen-lockfile 92 | 93 | - name: Build 94 | run: yarn build 95 | 96 | - name: Run Lint and Tests 97 | run: yarn test:full 98 | 99 | - name: Upload coverage reports 100 | uses: codecov/codecov-action@v1 101 | with: 102 | files: ./packages/jasmine-given/coverage/lcov.info, ./packages/jest-given/coverage/lcov.info 103 | 104 | - name: Configure CI Git User 105 | run: | 106 | git config --global user.name '@hirezio' 107 | git config --global user.email 'hirezio@users.noreply.github.com' 108 | 109 | - name: Update Version 110 | if: github.event_name == 'push' && github.ref == 'refs/heads/master' 111 | run: yarn lerna:version:ci 112 | 113 | - name: Check Authentication with Registry 114 | env: 115 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 116 | run: npm whoami 117 | 118 | - name: Publish to npm 119 | if: github.event_name == 'push' && github.ref == 'refs/heads/master' 120 | env: 121 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 122 | run: yarn lerna:publish 123 | -------------------------------------------------------------------------------- /packages/karma-jasmine-given/README.md: -------------------------------------------------------------------------------- 1 | # `@hirez_io/karma jasmine-given` ⚒ 2 | 3 | A karma plugin for loading [@hirez_io/jasmine-given](https://github.com/hirezio/given/tree/master/packages/jasmine-given) 4 | 5 | [![npm version](https://img.shields.io/npm/v/@hirez_io/karma-jasmine-given.svg?style=flat-square)](https://www.npmjs.org/package/@hirez_io/karma-jasmine-given) 6 | [![npm downloads](https://img.shields.io/npm/dm/@hirez_io/karma-jasmine-given.svg?style=flat-square)](http://npm-stat.com/charts.html?package=@hirez_io/karma-jasmine-given&from=2017-07-26) 7 | ![Build and optionally publish](https://github.com/hirezio/given/workflows/Build%20and%20optionally%20publish/badge.svg) 8 | [![lerna](https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg)](https://lerna.js.org/) 9 | [![Code of Conduct](https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square)](../../CODE_OF_CONDUCT.md) 10 | [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT) 11 | [![All Contributors](https://img.shields.io/badge/all_contributors-1-green.svg?style=flat-square)](#contributors-) 12 | 13 | 14 | 15 |
16 | 17 | TestAngular.com - Free Angular Testing Workshop - The Roadmap to Angular Testing Mastery 21 | 22 |
23 | 24 | ## Installation 25 | 26 | ``` 27 | yarn add -D @hirez_io/karma-jasmine-given 28 | ``` 29 | 30 | or 31 | 32 | ``` 33 | npm install -D @hirez_io/karma-jasmine-given 34 | ``` 35 | 36 | This plugin was inspired by [karma-jasmine-given](https://github.com/kirisu/karma-jasmine-given)) which loads the original "jasmine-given". 37 | 38 | I rewrote it to save you the hassle of loading @hirez_io/jasmine-given's script files yourself. 😎 39 | 40 | ## Configuration 41 | 42 | Here's how to modify your `karma.conf.js`: 43 | 44 | ```js 45 | // karma.conf.js 46 | 47 | module.exports = function(config) { 48 | config.set({ 49 | 50 | plugins: [ 51 | require('karma-jasmine'), 52 | require('@hirez_io/karma-jasmine-given'), // <-- ADD THIS 53 | require('karma-chrome-launcher') 54 | // other plugins you might have... 55 | ], 56 | 57 | frameworks: [ 58 | '@hirez_io/jasmine-given', // <-- ADD THIS 59 | 'jasmine', 60 | // other frameworks... 61 | ], 62 | 63 | // ... 64 | ``` 65 | 66 | Want to contribute? Yayy! 🎉 67 | 68 | Please read and follow our [Contributing Guidelines](../../CONTRIBUTING.md) to learn what are the right steps to take before contributing your time, effort and code. 69 | 70 | Thanks 🙏 71 | 72 | ## Code Of Conduct 73 | 74 | Be kind to each other and please read our [code of conduct](../../CODE_OF_CONDUCT.md). 75 | 76 | ## Contributors ✨ 77 | 78 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 |

Shai Reznik

💻 📖 🤔 🚇 🚧 🧑‍🏫 👀 ⚠️
88 | 89 | 90 | 91 | 92 | 93 | 94 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 95 | 96 | ## License 97 | 98 | MIT 99 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | We would love for you to contribute to this project. 4 | As a contributor, here are the guidelines we would like you to follow: 5 | 6 | ## Be Kind - Code of Conduct 7 | 8 | Help us keep this project open and inclusive. Please read and follow our [Code of Conduct](CODE_OF_CONDUCT.md) 9 | 10 | ## Found a bug? Want a feature? - Please submit an Issue 11 | 12 | [Choose an issue template](https://github.com/hirezio/given/issues/new/choose) to file a bug report / feature request. 13 | 14 | ## Want to contribute code? please submit a Pull Request (PR), but first... 15 | 16 | . 17 | 18 | ### ✅ 1. [Search this repo first](https://github.com/hirezio/given/pulls)... 19 | 20 | for an open or closed PR that relates to the change you want to introduce. 21 | 22 | . 23 | 24 | ### ✅ 2. **Before you start coding - find / create an issue** 25 | 26 | **Make sure there's an issue** describing the problem you're fixing, or documents the design for the feature you'd like to add. 27 | Discussing the design up front helps to ensure that we're ready to accept your work. 28 | 29 | **Don't waste your time working on code before you got a 👍 in an issue comment.** 30 | 31 | . 32 | 33 | ### ✅ 3. Fork the this repo and create a branch. 34 | 35 | - Hit that "Fork" button above (in this repo's github page). 36 | 37 | ![image](https://user-images.githubusercontent.com/1430726/95460679-ec014400-097d-11eb-9a7a-93e0262d37d9.png) 38 | 39 | - git clone your fork 40 | 41 | `git clone YOUR_FORK_URL` 42 | 43 | Get your url by from here 👇 44 | 45 | ![image](https://user-images.githubusercontent.com/1430726/95461173-94afa380-097e-11eb-9568-dc986e050de6.png) 46 | 47 | - Create a new branch locally in your fork's repo 48 | 49 | ```shell 50 | git checkout -b my-fix-branch master 51 | ``` 52 | 53 | ⚠ **IMPORTANT:** In this project the most important file is `shared/given-core/given-core.ts` - 54 | It is the actual implementation of both `jasmine-given` and `jest-given`. 55 | So if you change anything you need to verify that there is a test in both of the frameworks spec files. 56 | 57 | . 58 | 59 | ### ✅ 4. Make sure you add / modify tests 60 | 61 | Run `yarn test:full` to make sure there aren't any errors 62 | 63 | . 64 | 65 | ### ✅ 5. Commit your changes using commitizen: 66 | 67 | Instead of `git commit` use the following command: 68 | 69 | ```shell 70 | yarn commit 71 | ``` 72 | 73 | It will then ask you a bunch of questions. 74 | 75 | **For "scope" please choose from the following options:** 76 | 77 | | Scope name | Description | 78 | | ------------------- | --------------------------------------------------- | 79 | | core | a change related to the file `given-core.ts` | 80 | | jest-given | a change related to `@hirez_io/jest-given` | 81 | | jasmine-given | a change related to `@hirez_io/jasmine-given` | 82 | | karma-jasmine-given | a change related to `@hirez_io/karma-jasmine-given` | 83 | | global | any change that doesn't fall under the above scopes | 84 | 85 | This will create a descriptive commit message that follows the 86 | [Angular commit message convention](#commit-message-format). 87 | 88 | This is necessary to generate meaningful release notes / CHANGELOG automatically. 89 | 90 | . 91 | 92 | ### ✅ 6. Push your branch to GitHub: 93 | 94 | ```shell 95 | git push origin my-fix-branch 96 | ``` 97 | 98 | . 99 | 100 | ### ✅ 7. In GitHub, create a pull request for `hirezio/given:master`. 101 | 102 | Make sure you check the following checkbox "Allow edits from maintainers" - 103 | 104 | ![image](https://user-images.githubusercontent.com/1430726/95461503-fbcd5800-097e-11eb-9b55-321d1ff0e6bb.png) 105 | 106 | If you need to update your PR for some reason - 107 | 108 | - Make the required updates. 109 | 110 | - Re-run the tests to ensure tests are still passing `yarn test:full` 111 | 112 | - Rebase your branch and force push to your GitHub repository (this will update your Pull Request): 113 | 114 | ```shell 115 | git rebase master -i 116 | git push -f 117 | ``` 118 | 119 | . 120 | 121 | ### ✅ 8. After your pull request is merged - delete your PR branch 122 | 123 | After your pull request is merged, you can safely delete your branch and pull the changes from the main (upstream) repository: 124 | 125 | - Delete the remote branch on GitHub either through the GitHub web UI or your local shell as follows: 126 | 127 | ```shell 128 | git push origin --delete my-fix-branch 129 | ``` 130 | 131 | - Check out the master branch: 132 | 133 | ```shell 134 | git checkout master -f 135 | ``` 136 | 137 | - Delete the local branch: 138 | 139 | ```shell 140 | git branch -D my-fix-branch 141 | ``` 142 | 143 | - Update your master with the latest upstream version: 144 | 145 | ```shell 146 | git pull --ff upstream master 147 | ``` 148 | 149 | . 150 | 151 | ### ✅ 9. That's it! Thank you for your contribution! 🙏💓 152 | 153 | [commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit# 154 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributor Covenant Code of Conduct 3 | 4 | ## Our Pledge 5 | 6 | We as members, contributors, and leaders pledge to make participation in our 7 | community a harassment-free experience for everyone, regardless of age, body 8 | size, visible or invisible disability, ethnicity, sex characteristics, gender 9 | identity and expression, level of experience, education, socio-economic status, 10 | nationality, personal appearance, race, religion, or sexual identity 11 | and orientation. 12 | 13 | We pledge to act and interact in ways that contribute to an open, welcoming, 14 | diverse, inclusive, and healthy community. 15 | 16 | ## Our Standards 17 | 18 | Examples of behavior that contributes to a positive environment for our 19 | community include: 20 | 21 | * Demonstrating empathy and kindness toward other people 22 | * Being respectful of differing opinions, viewpoints, and experiences 23 | * Giving and gracefully accepting constructive feedback 24 | * Accepting responsibility and apologizing to those affected by our mistakes, 25 | and learning from the experience 26 | * Focusing on what is best not just for us as individuals, but for the 27 | overall community 28 | 29 | Examples of unacceptable behavior include: 30 | 31 | * The use of sexualized language or imagery, and sexual attention or 32 | advances of any kind 33 | * Trolling, insulting or derogatory comments, and personal or political attacks 34 | * Public or private harassment 35 | * Publishing others' private information, such as a physical or email 36 | address, without their explicit permission 37 | * Other conduct which could reasonably be considered inappropriate in a 38 | professional setting 39 | 40 | ## Enforcement Responsibilities 41 | 42 | Community leaders are responsible for clarifying and enforcing our standards of 43 | acceptable behavior and will take appropriate and fair corrective action in 44 | response to any behavior that they deem inappropriate, threatening, offensive, 45 | or harmful. 46 | 47 | Community leaders have the right and responsibility to remove, edit, or reject 48 | comments, commits, code, wiki edits, issues, and other contributions that are 49 | not aligned to this Code of Conduct, and will communicate reasons for moderation 50 | decisions when appropriate. 51 | 52 | ## Scope 53 | 54 | This Code of Conduct applies within all community spaces, and also applies when 55 | an individual is officially representing the community in public spaces. 56 | Examples of representing our community include using an official e-mail address, 57 | posting via an official social media account, or acting as an appointed 58 | representative at an online or offline event. 59 | 60 | ## Enforcement 61 | 62 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 63 | reported to the community leaders responsible for enforcement at 64 | conduct@hirez.io. 65 | All complaints will be reviewed and investigated promptly and fairly. 66 | 67 | All community leaders are obligated to respect the privacy and security of the 68 | reporter of any incident. 69 | 70 | ## Enforcement Guidelines 71 | 72 | Community leaders will follow these Community Impact Guidelines in determining 73 | the consequences for any action they deem in violation of this Code of Conduct: 74 | 75 | ### 1. Correction 76 | 77 | **Community Impact**: Use of inappropriate language or other behavior deemed 78 | unprofessional or unwelcome in the community. 79 | 80 | **Consequence**: A private, written warning from community leaders, providing 81 | clarity around the nature of the violation and an explanation of why the 82 | behavior was inappropriate. A public apology may be requested. 83 | 84 | ### 2. Warning 85 | 86 | **Community Impact**: A violation through a single incident or series 87 | of actions. 88 | 89 | **Consequence**: A warning with consequences for continued behavior. No 90 | interaction with the people involved, including unsolicited interaction with 91 | those enforcing the Code of Conduct, for a specified period of time. This 92 | includes avoiding interactions in community spaces as well as external channels 93 | like social media. Violating these terms may lead to a temporary or 94 | permanent ban. 95 | 96 | ### 3. Temporary Ban 97 | 98 | **Community Impact**: A serious violation of community standards, including 99 | sustained inappropriate behavior. 100 | 101 | **Consequence**: A temporary ban from any sort of interaction or public 102 | communication with the community for a specified period of time. No public or 103 | private interaction with the people involved, including unsolicited interaction 104 | with those enforcing the Code of Conduct, is allowed during this period. 105 | Violating these terms may lead to a permanent ban. 106 | 107 | ### 4. Permanent Ban 108 | 109 | **Community Impact**: Demonstrating a pattern of violation of community 110 | standards, including sustained inappropriate behavior, harassment of an 111 | individual, or aggression toward or disparagement of classes of individuals. 112 | 113 | **Consequence**: A permanent ban from any sort of public interaction within 114 | the community. 115 | 116 | ## Attribution 117 | 118 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 119 | version 2.0, available at 120 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 121 | 122 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 123 | enforcement ladder](https://github.com/mozilla/diversity). 124 | 125 | [homepage]: https://www.contributor-covenant.org 126 | 127 | For answers to common questions about this code of conduct, see the FAQ at 128 | https://www.contributor-covenant.org/faq. Translations are available at 129 | https://www.contributor-covenant.org/translations. 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # (jasmine | jest)-given Monorepo 2 | 3 | 4 | [![All Contributors](https://img.shields.io/badge/all_contributors-4-orange.svg?style=flat-square)](#contributors-) 5 | 6 | 7 | ## Packages 8 | 9 | This repository contains the HiRez.io's versions of: 10 | 11 | | Project | Status | Description | 12 | | ------------------------------- | -------------------------------------------------------------------------------- | ---------------------------------------------------- | 13 | | [@hirez_io/jest-given] | [![@hirez_io/jest-given-status]][@hirez_io/jest-given-package] | Jest addon that adds the "Given When Then" syntax | 14 | | [@hirez_io/jasmine-given] | [![@hirez_io/jasmine-given-status]][@hirez_io/jasmine-given-package] | Jasmine addon that adds the "Given When Then" syntax | 15 | | [@hirez_io/karma-jasmine-given] | [![@hirez_io/karma-jasmine-given-status]][@hirez_io/karma-jasmine-given-package] | Karma plugin for `@hirez_io/jasmine-given` | 16 | 17 | [@hirez_io/jest-given]: https://github.com/hirezio/given/tree/master/packages/jest-given 18 | [@hirez_io/jasmine-given]: https://github.com/hirezio/given/tree/master/packages/jasmine-given 19 | [@hirez_io/karma-jasmine-given]: https://github.com/hirezio/given/tree/master/packages/karma-jasmine-given 20 | [@hirez_io/jest-given-status]: https://img.shields.io/npm/v/@hirez_io/jest-given.svg 21 | [@hirez_io/jest-given-package]: https://npmjs.com/package/@hirez_io/jest-given 22 | [@hirez_io/jasmine-given-status]: https://img.shields.io/npm/v/@hirez_io/jasmine-given.svg 23 | [@hirez_io/jasmine-given-package]: https://npmjs.com/package/@hirez_io/jasmine-given 24 | [@hirez_io/karma-jasmine-given-status]: https://img.shields.io/npm/v/@hirez_io/karma-jasmine-given.svg 25 | [@hirez_io/karma-jasmine-given-package]: https://npmjs.com/package/@hirez_io/karma-jasmine-given 26 | 27 | ## Roadmap 28 | 29 | - [ ] Setup github actions to test, publish and collect coverage respectively 30 | - [ ] Add "FThen()? 31 | - [ ] Add more context to error messages (describe label from "this", or then label)? 32 | 33 | ## Prior Art + Credit 34 | 35 | The "Given" concept (and implementation) is based on the original [jasmine-given](https://github.com/searls/jasmine-given) library by [Justin Searls](https://twitter.com/searls) who've done an amazing job with it, which is in turn based on [rspec-given](https://github.com/jimweirich/rspec-given) by [Jim Weirich](https://twitter.com/jimweirich). 36 | 37 | ## Contributing 38 | 39 | Want to contribute? Yayy! 🎉 40 | 41 | Please read and follow our [Contributing Guidelines](CONTRIBUTING.md) to learn what are the right steps to take before contributing your time, effort and code. 42 | 43 | Thanks 🙏 44 | 45 | ## Code Of Conduct 46 | 47 | Be kind to each other and please read our [code of conduct](CODE_OF_CONDUCT.md). 48 | 49 | ## Want to learn more? 50 | 51 |
52 | 53 | TestAngular.com - Free Angular Testing Workshop - The Roadmap to Angular Testing Mastery 57 | 58 |
59 | 60 | ## Contributors ✨ 61 | 62 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 |
Shai Reznik
Shai Reznik

💻 📖 🤔 🚇 🚧 🧑‍🏫 👀 ⚠️
WynieCronje
WynieCronje

💻 ⚠️ 🚧
Yianen
Yianen

💻 ⚠️ 🚧
Keagan Fouché
Keagan Fouché

💻 🚧
77 | 78 | 79 | 80 | 81 | 82 | 83 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 84 | 85 | ## License 86 | 87 | MIT 88 | -------------------------------------------------------------------------------- /packages/jest-given/README.md: -------------------------------------------------------------------------------- 1 | # `@hirez_io/jest-given` 📃👌 2 | 3 | A jest addon that helps you clean up your microtests by breaking them into a **"Given / When / Then"** structure. 4 | 5 | [![npm version](https://img.shields.io/npm/v/@hirez_io/jest-given.svg?style=flat-square)](https://www.npmjs.org/package/@hirez_io/jest-given) 6 | [![npm downloads](https://img.shields.io/npm/dm/@hirez_io/jest-given.svg?style=flat-square)](http://npm-stat.com/charts.html?package=@hirez_io/jest-given&from=2017-07-26) 7 | [![codecov](https://img.shields.io/codecov/c/github/hirezio/given.svg)](https://codecov.io/gh/hirezio/given) 8 | ![Build and optionally publish](https://github.com/hirezio/given/workflows/Build%20and%20optionally%20publish/badge.svg) 9 | [![lerna](https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg)](https://lerna.js.org/) 10 | [![Code of Conduct](https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square)](../../CODE_OF_CONDUCT.md) 11 | [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT) 12 | [![All Contributors](https://img.shields.io/badge/all_contributors-2-green.svg?style=flat-square)](#contributors-) 13 | 14 | 15 | 16 | ## Installation 17 | 18 | ``` 19 | yarn add -D @hirez_io/jest-given 20 | ``` 21 | 22 | or 23 | 24 | ``` 25 | npm install -D @hirez_io/jest-given 26 | ``` 27 | 28 | ## Configuring Jest 29 | 30 | Add the following line to your jest config: 31 | 32 | ```json 33 | "setupFilesAfterEnv": ["node_modules/@hirez_io/jest-given/dist/jest-given.js"] 34 | ``` 35 | 36 | ⚠ **ATTENTION:** If you have configured `rootDir` - 37 | 38 | Make sure you have the right path to `node_modules`. 39 | 40 | For example: 41 | 42 | ```json 43 | "rootDir": "src", 44 | "setupFilesAfterEnv": ["../node_modules/@hirez_io/jest-given/dist/jest-given.js"] 45 | ``` 46 | 47 | . 48 | 49 | ## Using TypeScript? 50 | 51 | You should add `@hirez_io/jest-given` to your `types` property in your `tsconfig.json` (or `tsconfig.spec.json`) like this: 52 | 53 | ```js 54 | // tsconfig.json or tsconfig.spec.json 55 | 56 | { 57 | ... 58 | "types": [ 59 | "jest", 60 | "@hirez_io/jest-given", // <-- ADD THIS 61 | 62 | // ...any other types you might have... 63 | ], 64 | ... 65 | } 66 | ``` 67 | 68 | ⚠ **ATTENTION:** If you have `typeRoots` configured like this - 69 | 70 | ```ts 71 | "typeRoots": [ 72 | "node_modules/@types" 73 | ], 74 | ``` 75 | 76 | You should add `"node_modules"` like this - 77 | 78 | ```ts 79 | "typeRoots": [ 80 | "node_modules/@types", 81 | "node_modules/@hirez_io" // <-- ADD THIS 82 | ], 83 | ``` 84 | 85 | or else it won't find `@hirez_io/jest-given` global types. 86 | 87 | ⚠ **VS CODE USERS:** add the above configuration (`types` and/or `typeRoots`) to your `tsconfig.json` specifically or else it would not recognize the global types. 88 | 89 | . 90 | 91 | ## Prior Art + Credit 92 | 93 | This library is a port of [`@hirez_io/jasmine-given`](https://github.com/hirezio/given/tree/master/packages/jasmine-given) which is a rewrite of the original [jasmine-given](https://github.com/searls/jasmine-given) library by [Justin Searls](https://twitter.com/searls) who've done an amazing job with it. Checkout his company [TestDouble](https://testdouble.com) and their [blog](https://blog.testdouble.com). 94 | 95 | #### So why a rewrite and how is it different? 96 | 97 | [Everything is explained here](https://github.com/hirezio/given/tree/master/packages/jasmine-given#prior-art--credit) 😀 98 | 99 | . 100 | 101 | ## Why choose this over plain `beforeEach` and `it()` functions? 102 | 103 | ### ✅ **Cleaner structure:** 104 | 105 | Helps you break down tests into the natural "Arrange, Act, Assert" model via "Given When and Then" and by that enforces a "microtest" structure. 106 | 107 | ```ts 108 | describe('MyComponent', () => { 109 | let firstNum; 110 | let actualResult; 111 | 112 | // THIS IS EXACTLY LIKE A `beforeEach` 113 | // It's where you setup your code / inputs 114 | Given(() => { 115 | firstNum = 1; 116 | }); 117 | 118 | // THIS IS A SPECIAL TYPE OF `beforeEach` 119 | // It's where you call the action under test 120 | When(() => { 121 | actualResult = addTwo(firstNum); 122 | }); 123 | 124 | // THIS IS EXACTLY LIKE A `it()` 125 | // It's where you expect the desired outcome 126 | Then(() => { 127 | expect(actualResult).toEqual(3); 128 | }); 129 | 130 | // You can also add a message 131 | Then('it should be equal to 3', () => { 132 | expect(actualResult).toEqual(3); 133 | }); 134 | }); 135 | ``` 136 | 137 | #### It even supports `done` and `async` / `await` - 138 | 139 | ```ts 140 | describe('MyComponent', () => { 141 | let firstNum; 142 | let actualResult; 143 | 144 | // Supports "done" 145 | Given((done) => { 146 | firstNum = 1; 147 | done(); 148 | // you can also use done(err) or done.fail(err) if you need to 149 | }); 150 | 151 | // Supports "async/await" 152 | When(async () => { 153 | actualResult = await addTwo(firstNum); 154 | }); 155 | 156 | Then(() => { 157 | expect(actualResult).toEqual(3); 158 | }); 159 | }); 160 | ``` 161 | 162 | ### ✅ **Reusability:** 163 | 164 | By being able to extract the action (`When`) outside the `Given` & `Then` pairs, you are able to reuse the same action and save the same repetitive code. 165 | 166 | ```ts 167 | describe('MyComponent', () => { 168 | 169 | let firstNum; 170 | let actualResult; 171 | 172 | // Although the "When" is defined before the "Given" 173 | // it will run between each "Given" and "Then" 174 | // So it's like a "beforeEach" with special powers 175 | When(() => { 176 | console.log('WHEN'); 177 | actualResult = addTwo(firstNum); 178 | }) 179 | 180 | describe('GIVEN initial number is 1 THEN the result should be 3', () => { 181 | 182 | Given(() => { 183 | console.log('GIVEN #1'); 184 | firstNum = 1; 185 | }) 186 | 187 | Then(() => { 188 | console.log('THEN #1'); 189 | expect(actualResult).toEqual(3); 190 | 191 | }) 192 | }) 193 | 194 | describe('GIVEN initial number is 18 THEN the result should be 20', () => { 195 | 196 | Given(() => { 197 | console.log('GIVEN #2'); 198 | firstNum = 18; 199 | }) 200 | 201 | Then(() => { 202 | console.log('THEN #2'); 203 | expect(actualResult).toEqual(20); 204 | 205 | }) 206 | }) 207 | 208 | }) 209 | 210 | 211 | 212 | CONSOLE OUTPUT: 213 | -------------- 214 | 215 | GIVEN #1 216 | WHEN 217 | THEN #1 218 | 219 | GIVEN #2 220 | WHEN 221 | THEN #2 222 | 223 | 224 | ``` 225 | 226 | ### ✅ **Better test description:** 227 | 228 | The message for `it("should do something", ...)` focus specifically on the "outcome" (`Then`), but moving the description of the test into the `describe` gives you a chance to write a more descriptive test description. 229 | 230 | (as seen above) 231 | 232 | ## Contributing 233 | 234 | Want to contribute? Yayy! 🎉 235 | 236 | Please read and follow our [Contributing Guidelines](../../CONTRIBUTING.md) to learn what are the right steps to take before contributing your time, effort and code. 237 | 238 | Thanks 🙏 239 | 240 | ## Code Of Conduct 241 | 242 | Be kind to each other and please read our [code of conduct](../../CODE_OF_CONDUCT.md). 243 | 244 | ## Contributors ✨ 245 | 246 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 |

Shai Reznik

💻 📖 🤔 🚇 🚧 🧑‍🏫 👀 ⚠️

WynieCronje

💻 ⚠️ 🚧
257 | 258 | 259 | 260 | 261 | 262 | 263 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 264 | 265 | ## License 266 | 267 | MIT 268 | 269 | ## Want to learn more? 270 | 271 |
272 | 273 | TestAngular.com - Free Angular Testing Workshop - The Roadmap to Angular Testing Mastery 277 | 278 |
279 | -------------------------------------------------------------------------------- /packages/jasmine-given/README.md: -------------------------------------------------------------------------------- 1 | # `@hirez_io/jasmine-given` 📃👌 2 | 3 | A jasmine addon that helps you clean up your microtests by breaking them into a **"Given / When / Then"** structure. 4 | 5 | [![npm version](https://img.shields.io/npm/v/@hirez_io/jasmine-given.svg?style=flat-square)](https://www.npmjs.org/package/@hirez_io/jasmine-given) 6 | [![npm downloads](https://img.shields.io/npm/dm/@hirez_io/jasmine-given.svg?style=flat-square)](http://npm-stat.com/charts.html?package=@hirez_io/jasmine-given&from=2017-07-26) 7 | [![codecov](https://img.shields.io/codecov/c/github/hirezio/given.svg)](https://codecov.io/gh/hirezio/given) 8 | ![Build and optionally publish](https://github.com/hirezio/given/workflows/Build%20and%20optionally%20publish/badge.svg) 9 | [![lerna](https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg)](https://lerna.js.org/) 10 | [![Code of Conduct](https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square)](../../CODE_OF_CONDUCT.md) 11 | [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT) 12 | [![All Contributors](https://img.shields.io/badge/all_contributors-2-green.svg?style=flat-square)](#contributors-) 13 | 14 | 15 | 16 |
17 | 18 | TestAngular.com - Free Angular Testing Workshop - The Roadmap to Angular Testing Mastery 22 | 23 |
24 | 25 | ## Installation 26 | 27 | ``` 28 | yarn add -D @hirez_io/jasmine-given 29 | ``` 30 | 31 | or 32 | 33 | ``` 34 | npm install -D @hirez_io/jasmine-given 35 | ``` 36 | 37 | ### Using TypeScript? 38 | 39 | You should add `@hirez_io/jasmine-given` to your `types` property in your `tsconfig.json` (or `tsconfig.spec.json`) like this: 40 | 41 | ```js 42 | // tsconfig.json or tsconfig.spec.json 43 | 44 | { 45 | ... 46 | "types": [ 47 | "jasmine", 48 | "@hirez_io/jasmine-given", // <-- ADD THIS 49 | 50 | // ...any other types you might have... 51 | ], 52 | ... 53 | } 54 | ``` 55 | 56 | ⚠ **ATTENTION:** If you have `typeRoots` configured like this - 57 | 58 | ```ts 59 | "typeRoots": [ 60 | "node_modules/@types" 61 | ], 62 | ``` 63 | 64 | You should add `"node_modules"` like this - 65 | 66 | ```ts 67 | "typeRoots": [ 68 | "node_modules/@types", 69 | "node_modules/@hirez_io" // <-- ADD THIS 70 | ], 71 | ``` 72 | 73 | or else it won't find `@hirez_io/jasmine-given` global types. 74 | 75 | ⚠ **VS CODE USERS:** add the above configuration (`types` and/or `typeRoots`) to your `tsconfig.json` specifically or else it would not recognize the global types. 76 | 77 | ### Using karma? 78 | 79 | `@hirez_io/jasmine-given` has a dependency on `@hirez_io/karma-jasmine-given` which is a karma plugin (inspired by [karma-jasmine-given](https://github.com/kirisu/karma-jasmine-given)) I rewrote to save you the hassle of loading the library script yourself. 80 | 81 | So it will automatically installs `@hirez_io/karma-jasmine-given` for you 😎 82 | 83 | Here's how to modify your `karma.conf.js`: 84 | 85 | ```js 86 | // karma.conf.js 87 | 88 | module.exports = function(config) { 89 | config.set({ 90 | 91 | plugins: [ 92 | require('karma-jasmine'), 93 | require('@hirez_io/karma-jasmine-given'), // <-- ADD THIS 94 | require('karma-chrome-launcher') 95 | // other plugins you might have... 96 | ], 97 | 98 | frameworks: [ 99 | '@hirez_io/jasmine-given', // <-- ADD THIS 100 | 'jasmine', 101 | // other frameworks... 102 | ], 103 | 104 | // ... 105 | ``` 106 | 107 | ## Prior Art + Credit 108 | 109 | This library is a rewrite of the original [jasmine-given](https://github.com/searls/jasmine-given) library by [Justin Searls](https://twitter.com/searls) who've done an amazing job with it. Checkout his company [TestDouble](https://testdouble.com) and their [blog](https://blog.testdouble.com). 110 | 111 | #### So why a rewrite? 112 | 113 | Well.. because the original library is no longer maintained and was written in CoffeeScript, so I decided to rewrite it in TypeScript to make sure I could continue supporting it. 114 | 115 | Plus I fixed the error messages, removed less frequently used features and added support for newer features like async/await etc. 116 | 117 | ### How is it different from the original `jasmine-given`? 118 | 119 | **IMPROVEMENTS:** 120 | 121 | - ☑ Better error messages 122 | - ☑ Typescript instead of Coffeescript 123 | - ☑ Add **true support** for async / await 124 | - ☑ Wrapped sync functions as async to [prevent zalgo](https://blog.izs.me/2013/08/designing-apis-for-asynchrony) 125 | 126 | **BREAKING CHANGES:** 127 | I removed a bunch of features that I didn't really use that much over the years which also made this library more complicated to implement. 128 | 129 | - ⛔ `Add()` is removed 130 | - ⛔ `Invariant()` is removed 131 | 132 | ## Why choose this over plain `beforeEach` and `it()` functions? 133 | 134 | ### ✅ **Cleaner structure:** 135 | 136 | Helps you break down tests into the natural "Arrange, Act, Assert" model via "Given When and Then" and by that enforces a "microtest" structure. 137 | 138 | ```ts 139 | describe('MyComponent', () => { 140 | let firstNum; 141 | let actualResult; 142 | 143 | // THIS IS EXACTLY LIKE A `beforeEach` 144 | // It's where you setup your code / inputs 145 | Given(() => { 146 | firstNum = 1; 147 | }); 148 | 149 | // THIS IS A SPECIAL TYPE OF `beforeEach` 150 | // It's where you call the action under test 151 | When(() => { 152 | actualResult = addTwo(firstNum); 153 | }); 154 | 155 | // THIS IS EXACTLY LIKE A `it()` 156 | // It's where you expect the desired outcome 157 | Then(() => { 158 | expect(actualResult).toEqual(3); 159 | }); 160 | 161 | // You can also add a message 162 | Then('it should be equal to 3', () => { 163 | expect(actualResult).toEqual(3); 164 | }); 165 | }); 166 | ``` 167 | 168 | #### It even supports `done` and `async` / `await` - 169 | 170 | ```ts 171 | describe('MyComponent', () => { 172 | let firstNum; 173 | let actualResult; 174 | 175 | // Supports "done" 176 | Given((done) => { 177 | firstNum = 1; 178 | done(); 179 | // you can also use done(err) or done.fail(err) if you need to 180 | }); 181 | 182 | // Supports "async/await" 183 | When(async () => { 184 | actualResult = await addTwo(firstNum); 185 | }); 186 | 187 | Then(() => { 188 | expect(actualResult).toEqual(3); 189 | }); 190 | }); 191 | ``` 192 | 193 | ### ✅ **Reusability:** 194 | 195 | By being able to extract the action (`When`) outside the `Given` & `Then` pairs, you are able to reuse the same action and save the same repetitive code. 196 | 197 | ```ts 198 | describe('MyComponent', () => { 199 | 200 | let firstNum; 201 | let actualResult; 202 | 203 | // Although the "When" is defined before the "Given" 204 | // it will run between each "Given" and "Then" 205 | // So it's like a "beforeEach" with special powers 206 | When(() => { 207 | console.log('WHEN'); 208 | actualResult = addTwo(firstNum); 209 | }) 210 | 211 | describe('GIVEN initial number is 1 THEN the result should be 3', () => { 212 | 213 | Given(() => { 214 | console.log('GIVEN #1'); 215 | firstNum = 1; 216 | }) 217 | 218 | Then(() => { 219 | console.log('THEN #1'); 220 | expect(actualResult).toEqual(3); 221 | 222 | }) 223 | }) 224 | 225 | describe('GIVEN initial number is 18 THEN the result should be 20', () => { 226 | 227 | Given(() => { 228 | console.log('GIVEN #2'); 229 | firstNum = 18; 230 | }) 231 | 232 | Then(() => { 233 | console.log('THEN #2'); 234 | expect(actualResult).toEqual(20); 235 | 236 | }) 237 | }) 238 | 239 | }) 240 | 241 | 242 | 243 | CONSOLE OUTPUT: 244 | -------------- 245 | 246 | GIVEN #1 247 | WHEN 248 | THEN #1 249 | 250 | GIVEN #2 251 | WHEN 252 | THEN #2 253 | 254 | 255 | ``` 256 | 257 | ### ✅ **Better test description:** 258 | 259 | The message for `it("should do something", ...)` focus specifically on the "outcome" (`Then`), but moving the description of the test into the `describe` gives you a chance to write a more descriptive test description. 260 | 261 | (as seen above) 262 | 263 | ## Contributing 264 | 265 | Want to contribute? Yayy! 🎉 266 | 267 | Please read and follow our [Contributing Guidelines](../../CONTRIBUTING.md) to learn what are the right steps to take before contributing your time, effort and code. 268 | 269 | Thanks 🙏 270 | 271 | ## Code Of Conduct 272 | 273 | Be kind to each other and please read our [code of conduct](../../CODE_OF_CONDUCT.md). 274 | 275 | ## Contributors ✨ 276 | 277 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 |

Shai Reznik

💻 📖 🤔 🚇 🚧 🧑‍🏫 👀 ⚠️

WynieCronje

💻 ⚠️ 🚧
288 | 289 | 290 | 291 | 292 | 293 | 294 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 295 | 296 | ## License 297 | 298 | MIT 299 | -------------------------------------------------------------------------------- /packages/jest-given/spec/jest-given.spec.ts: -------------------------------------------------------------------------------- 1 | import { 2 | NO_SPEC_FUNCTION_ERROR, 3 | CONTEXT_FOR_GWT_ERROR, 4 | NO_STACK_ERROR, 5 | } from '../../../shared/given-core/given-core'; 6 | 7 | const root = (0, eval)('this'); 8 | 9 | describe('Jest Given', () => { 10 | let fakeNumber: number | undefined; 11 | let actualResult: any; 12 | 13 | function addTwo(num: number | undefined) { 14 | if (num) { 15 | return num + 2; 16 | } 17 | return undefined; 18 | } 19 | 20 | Given(() => { 21 | fakeNumber = undefined; 22 | actualResult = undefined; 23 | }); 24 | 25 | describe('should run "Given" before "When" and "When" before "Then"', () => { 26 | Given(() => { 27 | fakeNumber = 2; 28 | }); 29 | 30 | When(() => { 31 | actualResult = addTwo(fakeNumber); 32 | }); 33 | 34 | Then(() => { 35 | expect(actualResult).toBe(4); 36 | }); 37 | }); 38 | 39 | describe('should run the "When" after the "Given" even if declared in reverse', () => { 40 | When(() => { 41 | actualResult = addTwo(fakeNumber); 42 | }); 43 | 44 | Given(() => { 45 | fakeNumber = 2; 46 | }); 47 | 48 | Then(() => { 49 | expect(actualResult).toBe(4); 50 | }); 51 | }); 52 | 53 | describe('should run the "When" after the "Given" even if nested', () => { 54 | When(() => { 55 | actualResult = addTwo(fakeNumber); 56 | }); 57 | 58 | describe('even if nested', () => { 59 | Given(() => { 60 | fakeNumber = 2; 61 | }); 62 | 63 | Then(() => { 64 | expect(actualResult).toBe(4); 65 | }); 66 | }); 67 | }); 68 | 69 | describe('should run more than one "When" after the "Given"', () => { 70 | When(() => { 71 | fakeNumber = 10; 72 | }); 73 | 74 | When(() => { 75 | actualResult = addTwo(fakeNumber); 76 | }); 77 | 78 | describe('even if nested', () => { 79 | Given(() => { 80 | fakeNumber = 3; 81 | }); 82 | 83 | Then(() => { 84 | expect(actualResult).toBe(12); 85 | }); 86 | }); 87 | }); 88 | 89 | describe('should handle done function in "Given"', () => { 90 | Given((done) => { 91 | fakeNumber = 2; 92 | done(); 93 | }); 94 | 95 | When(() => { 96 | actualResult = addTwo(fakeNumber); 97 | }); 98 | 99 | Then(() => { 100 | expect(actualResult).toBe(4); 101 | }); 102 | }); 103 | 104 | describe('should support done function in "When"', () => { 105 | When((done) => { 106 | actualResult = addTwo(2); 107 | done(); 108 | }); 109 | 110 | Then(() => { 111 | expect(actualResult).toBe(4); 112 | }); 113 | }); 114 | 115 | describe('should support done function in "Then"', () => { 116 | Then((done) => { 117 | expect(true).toBe(true); 118 | done(); 119 | }); 120 | }); 121 | 122 | describe('should handle async await in "Given"', () => { 123 | Given(async () => { 124 | fakeNumber = await Promise.resolve(1); 125 | }); 126 | 127 | Given(async () => { 128 | fakeNumber = await Promise.resolve(2); 129 | }); 130 | 131 | When(() => { 132 | actualResult = addTwo(fakeNumber); 133 | }); 134 | 135 | Then(() => { 136 | expect(actualResult).toBe(4); 137 | }); 138 | }); 139 | 140 | describe('should handle async await in "When"', () => { 141 | When(async () => { 142 | fakeNumber = await Promise.resolve(1); 143 | }); 144 | 145 | When(async () => { 146 | fakeNumber = await Promise.resolve(2); 147 | actualResult = addTwo(fakeNumber); 148 | }); 149 | 150 | Then(() => { 151 | expect(actualResult).toBe(4); 152 | }); 153 | }); 154 | 155 | describe('should handle async await in "Then"', () => { 156 | When(() => { 157 | actualResult = addTwo(2); 158 | }); 159 | 160 | Then(async () => { 161 | const expectedResult = await Promise.resolve(4); 162 | expect(actualResult).toBe(expectedResult); 163 | }); 164 | }); 165 | 166 | describe('Then() should pass an empty string to it() given no label', () => { 167 | beforeEach(() => { 168 | const itSpy = jest.spyOn(root, 'it').mockImplementation(); 169 | Then(() => {}); 170 | const actualLabel = itSpy.mock.calls[0][0]; 171 | expect(actualLabel).toBe(''); 172 | }); 173 | it('fake test just to satisfy jest', () => {}); 174 | }); 175 | 176 | describe('Then() should be able to have a label', () => { 177 | it('should add the label', () => { 178 | const itSpy = jest.spyOn(root, 'it').mockImplementation(); 179 | Then('FAKE LABEL', () => {}); 180 | const actualLabel = itSpy.mock.calls[0][0]; 181 | expect(actualLabel).toBe('\n -> Then FAKE LABEL'); 182 | }); 183 | }); 184 | 185 | describe('Then() is called with only a label', () => { 186 | it('should throw when called', () => { 187 | function errorThrowingCall() { 188 | (Then as any)('FAKE MESSAGE'); 189 | } 190 | expect(errorThrowingCall).toThrowError(NO_SPEC_FUNCTION_ERROR); 191 | }); 192 | }); 193 | 194 | describe('if error is thrown in the "Given" should show a meaningful message', () => { 195 | const FAKE_ERROR = 'FAKE ERROR'; 196 | let actualPromiseFromGiven: Promise; 197 | 198 | beforeEach(() => { 199 | jest.spyOn(root, 'beforeEach').mockImplementation((fn: any) => { 200 | actualPromiseFromGiven = fn(); 201 | }); 202 | }); 203 | 204 | it('should work with a regular callback', async () => { 205 | Given(() => { 206 | throw new Error(FAKE_ERROR); 207 | }); 208 | try { 209 | await actualPromiseFromGiven; 210 | } catch (err: any) { 211 | expect(err.message).toContain(`${CONTEXT_FOR_GWT_ERROR} Given():`); 212 | expect(err.message).toContain(FAKE_ERROR); 213 | } 214 | }); 215 | 216 | it('should work with a done callback', async () => { 217 | Given((done) => { 218 | throw new Error(FAKE_ERROR); 219 | }); 220 | try { 221 | await actualPromiseFromGiven; 222 | } catch (err: any) { 223 | expect(err.message).toContain(`${CONTEXT_FOR_GWT_ERROR} Given():`); 224 | expect(err.message).toContain(FAKE_ERROR); 225 | } 226 | }); 227 | 228 | it('should work with a done callback with passed error', async () => { 229 | Given((done) => { 230 | done(new Error(FAKE_ERROR)); 231 | }); 232 | try { 233 | await actualPromiseFromGiven; 234 | } catch (err: any) { 235 | expect(err.message).toContain(`${CONTEXT_FOR_GWT_ERROR} Given():`); 236 | expect(err.message).toContain(FAKE_ERROR); 237 | } 238 | }); 239 | 240 | it('should work with a done callback with passed error via done.fail()', async () => { 241 | Given((done) => { 242 | done.fail(new Error(FAKE_ERROR)); 243 | }); 244 | try { 245 | await actualPromiseFromGiven; 246 | } catch (err: any) { 247 | expect(err.message).toContain(`${CONTEXT_FOR_GWT_ERROR} Given():`); 248 | expect(err.message).toContain(FAKE_ERROR); 249 | } 250 | }); 251 | 252 | it('should work with an async callback', async () => { 253 | Given(async () => { 254 | throw new Error(FAKE_ERROR); 255 | }); 256 | 257 | try { 258 | await actualPromiseFromGiven; 259 | } catch (err: any) { 260 | expect(err.message).toContain(`${CONTEXT_FOR_GWT_ERROR} Given():`); 261 | expect(err.message).toContain(FAKE_ERROR); 262 | } 263 | }); 264 | }); 265 | 266 | describe('if an error gets thrown in "When" or "Then"', () => { 267 | let afterEachCache: Function[]; 268 | let actualError: any; 269 | let actualPromiseReturnedFromIt: Promise; 270 | 271 | const FAKE_ERROR_MESSAGE = 'FAKE ERROR'; 272 | 273 | beforeEach(() => { 274 | actualError = undefined; 275 | afterEachCache = []; 276 | 277 | // make beforeEach run immediately when called inside the next "it" function 278 | jest.spyOn(root, 'beforeEach').mockImplementation((fn: any) => fn()); 279 | 280 | // queues up afterEach functions for cleanup purposes inside the next "it" function 281 | jest 282 | .spyOn(root, 'afterEach') 283 | .mockImplementation((fn: any) => afterEachCache.push(fn)); 284 | 285 | // Because jasmine queues up these function, 286 | // the following line will get called after all the "it" functions in this spec file will get called 287 | // The purpose is to enable us to run "it()" immediately inside of another "it callback" 288 | // which otherwise throws an error... 289 | jest.spyOn(root, 'it').mockImplementation((desc: any, fn: any) => { 290 | actualPromiseReturnedFromIt = fn(); 291 | }); 292 | }); 293 | 294 | it('should show a meaningful message if it was thrown in "When"', async () => { 295 | // without a "done" 296 | When(() => { 297 | throw new Error(FAKE_ERROR_MESSAGE); 298 | }); 299 | // We must call "Then" or else the logic of "When" won't be called 300 | Then(() => {}); 301 | 302 | try { 303 | await actualPromiseReturnedFromIt; 304 | } catch (err: any) { 305 | actualError = err; 306 | } finally { 307 | afterEachCache.forEach((fn) => fn()); 308 | } 309 | 310 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} When():`); 311 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 312 | }); 313 | 314 | it('should show a meaningful message if it was thrown in "When" with a "done"', async () => { 315 | // WITH a "done" 316 | When((done) => { 317 | throw new Error(FAKE_ERROR_MESSAGE); 318 | }); 319 | // We must call "Then" or else the logic of "When" won't be called 320 | Then(() => {}); 321 | 322 | try { 323 | await actualPromiseReturnedFromIt; 324 | } catch (err: any) { 325 | actualError = err; 326 | } finally { 327 | afterEachCache.forEach((fn) => fn()); 328 | } 329 | 330 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} When():`); 331 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 332 | }); 333 | 334 | it(`should show a meaningful message ONLY ONCE 335 | if thrown in "When" with a "done" 336 | after multiple "When's with "done"s`, async () => { 337 | When((done) => { 338 | done(); 339 | }); 340 | 341 | When((done) => { 342 | done(); 343 | }); 344 | 345 | When((done) => { 346 | throw new Error(FAKE_ERROR_MESSAGE); 347 | }); 348 | // We must call "Then" or else the logic of "When" won't be called 349 | Then(() => {}); 350 | 351 | try { 352 | await actualPromiseReturnedFromIt; 353 | } catch (err: any) { 354 | actualError = err; 355 | } finally { 356 | afterEachCache.forEach((fn) => fn()); 357 | } 358 | 359 | const howManyTimesTheContextMessageAppears = actualError.message.match( 360 | /An error was thrown in When\(\):/gm 361 | ).length; 362 | 363 | expect(howManyTimesTheContextMessageAppears).toBe(1); 364 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 365 | }); 366 | 367 | it(`should show a meaningful message if it was thrown in "When" with a "done" 368 | passed as a parameter`, async () => { 369 | // WITH a "done" 370 | When((done) => { 371 | done(new Error(FAKE_ERROR_MESSAGE)); 372 | }); 373 | Then(() => {}); 374 | 375 | try { 376 | await actualPromiseReturnedFromIt; 377 | } catch (err: any) { 378 | actualError = err; 379 | } finally { 380 | afterEachCache.forEach((fn) => fn()); 381 | } 382 | 383 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} When():`); 384 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 385 | }); 386 | 387 | it(`should show a meaningful message if it was thrown in "When" with a "done" 388 | passed via done.fail()`, async () => { 389 | // WITH a "done" 390 | When((done) => { 391 | done.fail(new Error(FAKE_ERROR_MESSAGE)); 392 | }); 393 | // We must call "Then" or else the logic of "When" won't be called 394 | Then(() => {}); 395 | 396 | try { 397 | await actualPromiseReturnedFromIt; 398 | } catch (err: any) { 399 | actualError = err; 400 | } finally { 401 | afterEachCache.forEach((fn) => fn()); 402 | } 403 | 404 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} When():`); 405 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 406 | }); 407 | 408 | it('should show a meaningful message if thrown as ERROR OBJECT in async "When"', async () => { 409 | When(() => {}); 410 | When(async () => { 411 | throw new Error(FAKE_ERROR_MESSAGE); 412 | }); 413 | // We must call "Then" or else the logic of "When" won't be called 414 | Then(() => {}); 415 | 416 | try { 417 | await actualPromiseReturnedFromIt; 418 | } catch (err: any) { 419 | actualError = err; 420 | } finally { 421 | afterEachCache.forEach((fn) => fn()); 422 | } 423 | 424 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} When():`); 425 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 426 | }); 427 | 428 | it('should show a meaningful message if thrown as STRING in async "When"', async () => { 429 | When(async () => { 430 | throw FAKE_ERROR_MESSAGE; 431 | }); 432 | // We must call "Then" or else the logic of "When" won't be called 433 | Then(() => {}); 434 | 435 | try { 436 | await actualPromiseReturnedFromIt; 437 | } catch (err: any) { 438 | actualError = err; 439 | } finally { 440 | afterEachCache.forEach((fn) => fn()); 441 | } 442 | 443 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} When():`); 444 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 445 | expect(actualError.message).toContain(NO_STACK_ERROR); 446 | }); 447 | 448 | it('should show the original Message and Stack trace', async () => { 449 | let errStack = ''; 450 | const errMessage = 'original_message'; 451 | 452 | When(async () => { 453 | const err = new Error(); 454 | errStack = err.stack || ''; 455 | err.message = errMessage; 456 | 457 | throw err; 458 | }); 459 | // We must call "Then" or else the logic of "When" won't be called 460 | Then(() => {}); 461 | 462 | try { 463 | await actualPromiseReturnedFromIt; 464 | } catch (err: any) { 465 | actualError = err; 466 | } finally { 467 | afterEachCache.forEach((fn) => fn()); 468 | } 469 | 470 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} When():`); 471 | expect(actualError.message).toContain(errMessage); 472 | expect(actualError.stack).toContain(errStack); 473 | }); 474 | 475 | it('should show a meaningful message if thrown as Object without stack in async "When"', async () => { 476 | When(async () => { 477 | throw { message: FAKE_ERROR_MESSAGE }; 478 | }); 479 | // We must call "Then" or else the logic of "When" won't be called 480 | Then(() => {}); 481 | 482 | try { 483 | await actualPromiseReturnedFromIt; 484 | } catch (err: any) { 485 | actualError = err; 486 | } finally { 487 | afterEachCache.forEach((fn) => fn()); 488 | } 489 | 490 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} When():`); 491 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 492 | }); 493 | 494 | it('should show a meaningful message if it was thrown in "Then"', async () => { 495 | When(() => {}); 496 | 497 | Then(() => { 498 | throw new Error(FAKE_ERROR_MESSAGE); 499 | }); 500 | 501 | try { 502 | await actualPromiseReturnedFromIt; 503 | } catch (err: any) { 504 | actualError = err; 505 | } finally { 506 | afterEachCache.forEach((fn) => fn()); 507 | } 508 | 509 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} Then():`); 510 | expect(actualError.message).not.toContain('When():'); 511 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 512 | }); 513 | 514 | it('should show a meaningful message if it was thrown in "Then" with "done"', async () => { 515 | When(() => {}); 516 | 517 | // WITH a "done" 518 | Then((done) => { 519 | throw new Error(FAKE_ERROR_MESSAGE); 520 | }); 521 | 522 | try { 523 | await actualPromiseReturnedFromIt; 524 | } catch (err: any) { 525 | actualError = err; 526 | } finally { 527 | afterEachCache.forEach((fn) => fn()); 528 | } 529 | 530 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} Then():`); 531 | expect(actualError.message).not.toContain('When():'); 532 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 533 | }); 534 | 535 | it(`should show a meaningful message if it was thrown in "Then" with a "done" 536 | passed as a parameter to "done"`, async () => { 537 | Then((done) => { 538 | done(new Error(FAKE_ERROR_MESSAGE)); 539 | }); 540 | 541 | try { 542 | await actualPromiseReturnedFromIt; 543 | } catch (err: any) { 544 | actualError = err; 545 | } finally { 546 | afterEachCache.forEach((fn) => fn()); 547 | } 548 | 549 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} Then():`); 550 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 551 | }); 552 | 553 | it(`should show a meaningful message if it was thrown in "Then" with a "done" 554 | passed via done.fail()`, async () => { 555 | Then((done) => { 556 | done.fail(new Error(FAKE_ERROR_MESSAGE)); 557 | }); 558 | 559 | try { 560 | await actualPromiseReturnedFromIt; 561 | } catch (err: any) { 562 | actualError = err; 563 | } finally { 564 | afterEachCache.forEach((fn) => fn()); 565 | } 566 | 567 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} Then():`); 568 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 569 | }); 570 | 571 | it('should show a meaningful message if thrown as ERROR OBJECT in async "Then"', async () => { 572 | When(() => {}); 573 | Then(async () => { 574 | throw new Error(FAKE_ERROR_MESSAGE); 575 | }); 576 | 577 | try { 578 | await actualPromiseReturnedFromIt; 579 | } catch (err: any) { 580 | actualError = err; 581 | } finally { 582 | afterEachCache.forEach((fn) => fn()); 583 | } 584 | 585 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} Then():`); 586 | expect(actualError.message).not.toContain('When():'); 587 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 588 | }); 589 | }); 590 | }); 591 | -------------------------------------------------------------------------------- /packages/jasmine-given/spec/jasmine-given.spec.ts: -------------------------------------------------------------------------------- 1 | import { 2 | NO_SPEC_FUNCTION_ERROR, 3 | NO_STACK_ERROR, 4 | CONTEXT_FOR_GWT_ERROR, 5 | } from '../../../shared/given-core/given-core'; 6 | 7 | const root = (0, eval)('this'); 8 | 9 | describe('Jasmine Given', () => { 10 | let fakeNumber: number | undefined; 11 | let actualResult: any; 12 | 13 | function addTwo(num: number | undefined) { 14 | if (num) { 15 | return num + 2; 16 | } 17 | return undefined; 18 | } 19 | 20 | Given(() => { 21 | fakeNumber = undefined; 22 | actualResult = undefined; 23 | }); 24 | 25 | describe('should run "Given" before "When" and "When" before "Then"', () => { 26 | Given(() => { 27 | fakeNumber = 2; 28 | }); 29 | 30 | When(() => { 31 | actualResult = addTwo(fakeNumber); 32 | }); 33 | 34 | Then(() => { 35 | expect(actualResult).toBe(4); 36 | }); 37 | }); 38 | 39 | describe('should run the "When" after the "Given" even if declared in reverse', () => { 40 | When(() => { 41 | actualResult = addTwo(fakeNumber); 42 | }); 43 | 44 | Given(() => { 45 | fakeNumber = 2; 46 | }); 47 | 48 | Then(() => { 49 | expect(actualResult).toBe(4); 50 | }); 51 | }); 52 | 53 | describe('should run the "When" after the "Given" even if nested', () => { 54 | When(() => { 55 | actualResult = addTwo(fakeNumber); 56 | }); 57 | 58 | describe('even if nested', () => { 59 | Given(() => { 60 | fakeNumber = 2; 61 | }); 62 | 63 | Then(() => { 64 | expect(actualResult).toBe(4); 65 | }); 66 | }); 67 | }); 68 | 69 | describe('should run more than one "When" after the "Given"', () => { 70 | When(() => { 71 | fakeNumber = 10; 72 | }); 73 | 74 | When(() => { 75 | actualResult = addTwo(fakeNumber); 76 | }); 77 | 78 | describe('even if nested', () => { 79 | Given(() => { 80 | fakeNumber = 3; 81 | }); 82 | 83 | Then(() => { 84 | expect(actualResult).toBe(12); 85 | }); 86 | }); 87 | }); 88 | 89 | describe('should handle done function in "Given"', () => { 90 | Given((done) => { 91 | fakeNumber = 2; 92 | done(); 93 | }); 94 | 95 | When(() => { 96 | actualResult = addTwo(fakeNumber); 97 | }); 98 | 99 | Then(() => { 100 | expect(actualResult).toBe(4); 101 | }); 102 | }); 103 | 104 | describe('should support done function in "When"', () => { 105 | When((done) => { 106 | actualResult = addTwo(2); 107 | done(); 108 | }); 109 | 110 | Then(() => { 111 | expect(actualResult).toBe(4); 112 | }); 113 | }); 114 | 115 | describe('should support done function in "Then"', () => { 116 | Then((done) => { 117 | expect(true).toBe(true); 118 | done(); 119 | }); 120 | }); 121 | 122 | describe('should handle async await in "Given"', () => { 123 | Given(async () => { 124 | fakeNumber = await Promise.resolve(1); 125 | }); 126 | 127 | Given(async () => { 128 | fakeNumber = await Promise.resolve(2); 129 | }); 130 | 131 | When(() => { 132 | actualResult = addTwo(fakeNumber); 133 | }); 134 | 135 | Then(() => { 136 | expect(actualResult).toBe(4); 137 | }); 138 | }); 139 | 140 | describe('should handle async await in "When"', () => { 141 | When(async () => { 142 | fakeNumber = await Promise.resolve(1); 143 | }); 144 | 145 | When(async () => { 146 | fakeNumber = await Promise.resolve(2); 147 | actualResult = addTwo(fakeNumber); 148 | }); 149 | 150 | Then(() => { 151 | expect(actualResult).toBe(4); 152 | }); 153 | }); 154 | 155 | describe('should handle async await in "Then"', () => { 156 | When(() => { 157 | actualResult = addTwo(2); 158 | }); 159 | 160 | Then(async () => { 161 | const expectedResult = await Promise.resolve(4); 162 | expect(actualResult).toBe(expectedResult); 163 | }); 164 | }); 165 | 166 | describe('Then() should pass an empty string to it() given no label', () => { 167 | it('should not add the label', () => { 168 | spyOn(root, 'it'); 169 | Then(() => {}); 170 | const actualLabel = (it as jasmine.Spy).calls.first().args[0]; 171 | expect(actualLabel).toBe(''); 172 | }); 173 | }); 174 | 175 | describe('Then() should be able to have a label', () => { 176 | it('should add the label', () => { 177 | spyOn(root, 'it'); 178 | Then('FAKE LABEL', () => {}); 179 | const actualLabel = (it as jasmine.Spy).calls.first().args[0]; 180 | expect(actualLabel).toBe('\n -> Then FAKE LABEL'); 181 | }); 182 | }); 183 | 184 | describe('Then() is called with only a label', () => { 185 | it('should throw when called', () => { 186 | function errorThrowingCall() { 187 | (Then as any)('FAKE MESSAGE'); 188 | } 189 | expect(errorThrowingCall).toThrowError(NO_SPEC_FUNCTION_ERROR); 190 | }); 191 | }); 192 | 193 | describe('should share "this" context', () => { 194 | Given(function () { 195 | this.fakeInitialNumber = 2; 196 | this.expectedResult = 4; 197 | }); 198 | 199 | When(function () { 200 | actualResult = addTwo(this.fakeInitialNumber); 201 | }); 202 | 203 | Then(function () { 204 | expect(actualResult).toEqual(this.expectedResult); 205 | }); 206 | }); 207 | 208 | describe('if error is thrown in the "Given" should show a meaningful message', () => { 209 | const FAKE_ERROR = 'FAKE ERROR'; 210 | let actualPromiseFromGiven: Promise; 211 | 212 | beforeEach(() => { 213 | spyOn(root, 'beforeEach').and.callFake((fn: Function) => { 214 | actualPromiseFromGiven = fn(); 215 | }); 216 | }); 217 | 218 | it('should work with a regular callback', async () => { 219 | Given(() => { 220 | throw new Error(FAKE_ERROR); 221 | }); 222 | try { 223 | await actualPromiseFromGiven; 224 | } catch (err: any) { 225 | expect(err.message).toContain(`${CONTEXT_FOR_GWT_ERROR} Given():`); 226 | expect(err.message).toContain(FAKE_ERROR); 227 | } 228 | }); 229 | 230 | it('should work with a done callback', async () => { 231 | Given((done) => { 232 | throw new Error(FAKE_ERROR); 233 | }); 234 | try { 235 | await actualPromiseFromGiven; 236 | } catch (err: any) { 237 | expect(err.message).toContain(`${CONTEXT_FOR_GWT_ERROR} Given():`); 238 | expect(err.message).toContain(FAKE_ERROR); 239 | } 240 | }); 241 | 242 | it('should work with a done callback with passed error', async () => { 243 | Given((done) => { 244 | done(new Error(FAKE_ERROR)); 245 | }); 246 | try { 247 | await actualPromiseFromGiven; 248 | } catch (err: any) { 249 | expect(err.message).toContain(`${CONTEXT_FOR_GWT_ERROR} Given():`); 250 | expect(err.message).toContain(FAKE_ERROR); 251 | } 252 | }); 253 | 254 | it('should work with a done callback with passed error via done.fail()', async () => { 255 | Given((done) => { 256 | done.fail(new Error(FAKE_ERROR)); 257 | }); 258 | try { 259 | await actualPromiseFromGiven; 260 | } catch (err: any) { 261 | expect(err.message).toContain(`${CONTEXT_FOR_GWT_ERROR} Given():`); 262 | expect(err.message).toContain(FAKE_ERROR); 263 | } 264 | }); 265 | 266 | it('should work with an async callback', async () => { 267 | Given(async () => { 268 | throw new Error(FAKE_ERROR); 269 | }); 270 | 271 | try { 272 | await actualPromiseFromGiven; 273 | } catch (err: any) { 274 | expect(err.message).toContain(`${CONTEXT_FOR_GWT_ERROR} Given():`); 275 | expect(err.message).toContain(FAKE_ERROR); 276 | } 277 | }); 278 | }); 279 | 280 | describe('if an error gets thrown in "When" or "Then"', () => { 281 | let afterEachCache: Function[]; 282 | let actualError: any; 283 | let actualPromiseReturnedFromIt: Promise; 284 | 285 | const FAKE_ERROR_MESSAGE = 'FAKE ERROR'; 286 | 287 | beforeEach(() => { 288 | actualError = undefined; 289 | afterEachCache = []; 290 | 291 | // make beforeEach run immediately when called inside the next "it" function 292 | spyOn(root, 'beforeEach').and.callFake((fn: Function) => fn()); 293 | 294 | // queues up afterEach functions for cleanup purposes inside the next "it" function 295 | spyOn(root, 'afterEach').and.callFake((fn: Function) => afterEachCache.push(fn)); 296 | 297 | // Because jasmine queues up these function, 298 | // the following line will get called after all the "it" functions in this spec file will get called 299 | // The purpose is to enable us to run "it()" immediately inside of another "it callback" 300 | // which otherwise throws an error... 301 | spyOn(root, 'it').and.callFake((desc: string, fn: Function) => { 302 | actualPromiseReturnedFromIt = fn(); 303 | }); 304 | }); 305 | 306 | it('should show a meaningful message if it was thrown in "When"', async () => { 307 | // without a "done" 308 | When(() => { 309 | throw new Error(FAKE_ERROR_MESSAGE); 310 | }); 311 | // We must call "Then" or else the logic of "When" won't be called 312 | Then(() => {}); 313 | 314 | try { 315 | await actualPromiseReturnedFromIt; 316 | } catch (err: any) { 317 | actualError = err; 318 | } finally { 319 | afterEachCache.forEach((fn) => fn()); 320 | } 321 | 322 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} When():`); 323 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 324 | }); 325 | 326 | it('should show a meaningful message if it was thrown in "When" with a "done"', async () => { 327 | // WITH a "done" 328 | When((done) => { 329 | throw new Error(FAKE_ERROR_MESSAGE); 330 | }); 331 | // We must call "Then" or else the logic of "When" won't be called 332 | Then(() => {}); 333 | 334 | try { 335 | await actualPromiseReturnedFromIt; 336 | } catch (err: any) { 337 | actualError = err; 338 | } finally { 339 | afterEachCache.forEach((fn) => fn()); 340 | } 341 | 342 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} When():`); 343 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 344 | }); 345 | 346 | it(`should show a meaningful message ONLY ONCE 347 | if thrown in "When" with a "done" 348 | after multiple "When's with "done"s`, async () => { 349 | When((done) => { 350 | done(); 351 | }); 352 | 353 | When((done) => { 354 | done(); 355 | }); 356 | 357 | When((done) => { 358 | throw new Error(FAKE_ERROR_MESSAGE); 359 | }); 360 | // We must call "Then" or else the logic of "When" won't be called 361 | Then(() => {}); 362 | 363 | try { 364 | await actualPromiseReturnedFromIt; 365 | } catch (err: any) { 366 | actualError = err; 367 | } finally { 368 | afterEachCache.forEach((fn) => fn()); 369 | } 370 | 371 | const howManyTimesTheContextMessageAppears = actualError.message.match( 372 | /An error was thrown in When\(\):/gm 373 | ).length; 374 | 375 | expect(howManyTimesTheContextMessageAppears).toBe(1); 376 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 377 | }); 378 | 379 | it(`should show a meaningful message if it was thrown in "When" with a "done" 380 | passed as a parameter`, async () => { 381 | // WITH a "done" 382 | When((done) => { 383 | done(new Error(FAKE_ERROR_MESSAGE)); 384 | }); 385 | Then(() => {}); 386 | 387 | try { 388 | await actualPromiseReturnedFromIt; 389 | } catch (err: any) { 390 | actualError = err; 391 | } finally { 392 | afterEachCache.forEach((fn) => fn()); 393 | } 394 | 395 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} When():`); 396 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 397 | }); 398 | 399 | it(`should show a meaningful message if it was thrown in "When" with a "done" 400 | passed via done.fail()`, async () => { 401 | // WITH a "done" 402 | When((done) => { 403 | done.fail(new Error(FAKE_ERROR_MESSAGE)); 404 | }); 405 | // We must call "Then" or else the logic of "When" won't be called 406 | Then(() => {}); 407 | 408 | try { 409 | await actualPromiseReturnedFromIt; 410 | } catch (err: any) { 411 | actualError = err; 412 | } finally { 413 | afterEachCache.forEach((fn) => fn()); 414 | } 415 | 416 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} When():`); 417 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 418 | }); 419 | 420 | it('should show a meaningful message if thrown as ERROR OBJECT in async "When"', async () => { 421 | When(() => {}); 422 | When(async () => { 423 | throw new Error(FAKE_ERROR_MESSAGE); 424 | }); 425 | // We must call "Then" or else the logic of "When" won't be called 426 | Then(() => {}); 427 | 428 | try { 429 | await actualPromiseReturnedFromIt; 430 | } catch (err: any) { 431 | actualError = err; 432 | } finally { 433 | afterEachCache.forEach((fn) => fn()); 434 | } 435 | 436 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} When():`); 437 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 438 | }); 439 | 440 | it('should show a meaningful message if thrown as STRING in async "When"', async () => { 441 | When(async () => { 442 | throw FAKE_ERROR_MESSAGE; 443 | }); 444 | // We must call "Then" or else the logic of "When" won't be called 445 | Then(() => {}); 446 | 447 | try { 448 | await actualPromiseReturnedFromIt; 449 | } catch (err: any) { 450 | actualError = err; 451 | } finally { 452 | afterEachCache.forEach((fn) => fn()); 453 | } 454 | 455 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} When():`); 456 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 457 | expect(actualError.message).toContain(NO_STACK_ERROR); 458 | }); 459 | 460 | it('should show the original Message and Stack trace', async () => { 461 | let errStack = ''; 462 | const errMessage = 'original_message'; 463 | 464 | When(async () => { 465 | const err = new Error(); 466 | errStack = err.stack || ''; 467 | err.message = errMessage; 468 | 469 | throw err; 470 | }); 471 | // We must call "Then" or else the logic of "When" won't be called 472 | Then(() => {}); 473 | 474 | try { 475 | await actualPromiseReturnedFromIt; 476 | } catch (err: any) { 477 | actualError = err; 478 | } finally { 479 | afterEachCache.forEach((fn) => fn()); 480 | } 481 | console.log('actualError', actualError); 482 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} When():`); 483 | expect(actualError.message).toContain(errMessage); 484 | expect(actualError.stack).toContain(errStack); 485 | }); 486 | 487 | it('should show a meaningful message if thrown as Object without stack in async "When"', async () => { 488 | When(async () => { 489 | throw { message: FAKE_ERROR_MESSAGE }; 490 | }); 491 | // We must call "Then" or else the logic of "When" won't be called 492 | Then(() => {}); 493 | 494 | try { 495 | await actualPromiseReturnedFromIt; 496 | } catch (err: any) { 497 | actualError = err; 498 | } finally { 499 | afterEachCache.forEach((fn) => fn()); 500 | } 501 | 502 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} When():`); 503 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 504 | }); 505 | 506 | it('should show a meaningful message if it was thrown in "Then"', async () => { 507 | When(() => {}); 508 | 509 | Then(() => { 510 | throw new Error(FAKE_ERROR_MESSAGE); 511 | }); 512 | 513 | try { 514 | await actualPromiseReturnedFromIt; 515 | } catch (err: any) { 516 | actualError = err; 517 | } finally { 518 | afterEachCache.forEach((fn) => fn()); 519 | } 520 | 521 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} Then():`); 522 | expect(actualError.message).not.toContain('When():'); 523 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 524 | }); 525 | 526 | it('should show a meaningful message if it was thrown in "Then" with "done"', async () => { 527 | When(() => {}); 528 | 529 | // WITH a "done" 530 | Then((done) => { 531 | throw new Error(FAKE_ERROR_MESSAGE); 532 | }); 533 | 534 | try { 535 | await actualPromiseReturnedFromIt; 536 | } catch (err: any) { 537 | actualError = err; 538 | } finally { 539 | afterEachCache.forEach((fn) => fn()); 540 | } 541 | 542 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} Then():`); 543 | expect(actualError.message).not.toContain('When():'); 544 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 545 | }); 546 | 547 | it(`should show a meaningful message if it was thrown in "Then" with a "done" 548 | passed as a parameter to "done"`, async () => { 549 | Then((done) => { 550 | done(new Error(FAKE_ERROR_MESSAGE)); 551 | }); 552 | 553 | try { 554 | await actualPromiseReturnedFromIt; 555 | } catch (err: any) { 556 | actualError = err; 557 | } finally { 558 | afterEachCache.forEach((fn) => fn()); 559 | } 560 | 561 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} Then():`); 562 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 563 | }); 564 | 565 | it(`should show a meaningful message if it was thrown in "Then" with a "done" 566 | passed via done.fail()`, async () => { 567 | Then((done) => { 568 | done.fail(new Error(FAKE_ERROR_MESSAGE)); 569 | }); 570 | 571 | try { 572 | await actualPromiseReturnedFromIt; 573 | } catch (err: any) { 574 | actualError = err; 575 | } finally { 576 | afterEachCache.forEach((fn) => fn()); 577 | } 578 | 579 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} Then():`); 580 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 581 | }); 582 | 583 | it('should show a meaningful message if thrown as ERROR OBJECT in async "Then"', async () => { 584 | When(() => {}); 585 | Then(async () => { 586 | throw new Error(FAKE_ERROR_MESSAGE); 587 | }); 588 | 589 | try { 590 | await actualPromiseReturnedFromIt; 591 | } catch (err: any) { 592 | actualError = err; 593 | } finally { 594 | afterEachCache.forEach((fn) => fn()); 595 | } 596 | 597 | expect(actualError.message).toContain(`${CONTEXT_FOR_GWT_ERROR} Then():`); 598 | expect(actualError.message).not.toContain('When():'); 599 | expect(actualError.message).toContain(FAKE_ERROR_MESSAGE); 600 | }); 601 | }); 602 | }); 603 | --------------------------------------------------------------------------------