mirror of
				https://github.com/microsoft/playwright.git
				synced 2025-06-26 21:40:17 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			856 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			856 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| const { TestRunner } = require('../TestRunner');
 | |
| const { TestCollector, FocusedFilter, Repeater } = require('../TestCollector');
 | |
| const { TestExpectation, Environment } = require('../Test');
 | |
| 
 | |
| class Runner {
 | |
|   constructor(options = {}) {
 | |
|     this._options = options;
 | |
|     this._filter = new FocusedFilter();
 | |
|     this._repeater = new Repeater();
 | |
|     this._collector = new TestCollector(options);
 | |
|     this._collector.addSuiteAttribute('only', s => this._filter.markFocused(s));
 | |
|     this._collector.addTestAttribute('only', t => this._filter.markFocused(t));
 | |
|     this._collector.addSuiteAttribute('skip', s => s.setSkipped(true));
 | |
|     this._collector.addTestAttribute('skip', t => t.setSkipped(true));
 | |
|     this._collector.addTestAttribute('fail', t => t.setExpectation(t.Expectations.Fail));
 | |
|     this._collector.addSuiteModifier('repeat', (s, count) => this._repeater.repeat(s, count));
 | |
|     this._collector.addTestModifier('repeat', (t, count) => this._repeater.repeat(t, count));
 | |
| 
 | |
|     const api = this._collector.api();
 | |
|     for (const [key, value] of Object.entries(api))
 | |
|       this[key] = value;
 | |
|     this.fdescribe = api.describe.only;
 | |
|     this.xdescribe = api.describe.skip;
 | |
|     this.fit = api.it.only;
 | |
|     this.xit = api.it.skip;
 | |
|     this.Expectations = { ...TestExpectation };
 | |
|   }
 | |
| 
 | |
|   createTestRuns() {
 | |
|     return this._repeater.createTestRuns(this._filter.filter(this._collector.tests()));
 | |
|   }
 | |
| 
 | |
|   run() {
 | |
|     this._testRunner = new TestRunner();
 | |
|     return this._testRunner.run(this.createTestRuns(), this._options);
 | |
|   }
 | |
| 
 | |
|   tests() {
 | |
|     return this._collector.tests();
 | |
|   }
 | |
| 
 | |
|   focusedTests() {
 | |
|     return this._filter.focusedTests(this._collector.tests());
 | |
|   }
 | |
| 
 | |
|   suites() {
 | |
|     return this._collector.suites();
 | |
|   }
 | |
| 
 | |
|   focusedSuites() {
 | |
|     return this._filter.focusedSuites(this._collector.suites());
 | |
|   }
 | |
| 
 | |
|   terminate() {
 | |
|     this._testRunner.terminate();
 | |
|   }
 | |
| }
 | |
| 
 | |
| module.exports.addTests = function({describe, fdescribe, xdescribe, it, xit, fit, expect}) {
 | |
|   describe('TestRunner.it', () => {
 | |
|     it('should declare a test', async() => {
 | |
|       const t = new Runner();
 | |
|       t.it('uno', () => {});
 | |
|       expect(t.tests().length).toBe(1);
 | |
|       const test = t.tests()[0];
 | |
|       expect(test.name()).toBe('uno');
 | |
|       expect(test.fullName()).toBe('uno');
 | |
|       expect(test.skipped()).toBe(false);
 | |
|       expect(test.location().filePath()).toEqual(__filename);
 | |
|       expect(test.location().fileName()).toEqual('testrunner.spec.js');
 | |
|       expect(test.location().lineNumber()).toBeTruthy();
 | |
|       expect(test.location().columnNumber()).toBeTruthy();
 | |
|     });
 | |
|     it('should run a test', async() => {
 | |
|       const t = new Runner();
 | |
|       t.it('uno', () => {});
 | |
|       const result = await t.run();
 | |
|       expect(result.runs.length).toBe(1);
 | |
|       expect(result.runs[0].test()).toBe(t.tests()[0]);
 | |
|       expect(result.runs[0].result()).toBe('ok');
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('TestRunner.xit', () => {
 | |
|     it('should declare a skipped test', async() => {
 | |
|       const t = new Runner();
 | |
|       t.xit('uno', () => {});
 | |
|       expect(t.tests().length).toBe(1);
 | |
|       const test = t.tests()[0];
 | |
|       expect(test.name()).toBe('uno');
 | |
|       expect(test.fullName()).toBe('uno');
 | |
|       expect(test.skipped()).toBe(true);
 | |
|     });
 | |
|     it('should not run a skipped test', async() => {
 | |
|       const t = new Runner();
 | |
|       t.xit('uno', () => {});
 | |
|       const result = await t.run();
 | |
|       expect(result.runs.length).toBe(1);
 | |
|       expect(result.runs[0].test()).toBe(t.tests()[0]);
 | |
|       expect(result.runs[0].result()).toBe('skipped');
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('TestRunner.fit', () => {
 | |
|     it('should declare a focused test', async() => {
 | |
|       const t = new Runner();
 | |
|       t.fit('uno', () => {});
 | |
|       expect(t.tests().length).toBe(1);
 | |
|       const test = t.tests()[0];
 | |
|       expect(test.name()).toBe('uno');
 | |
|       expect(test.fullName()).toBe('uno');
 | |
|       expect(test.skipped()).toBe(false);
 | |
|       expect(t.focusedTests()[0]).toBe(test);
 | |
|     });
 | |
|     it('should run a focused test', async() => {
 | |
|       const t = new Runner();
 | |
|       t.fit('uno', () => {});
 | |
|       const result = await t.run();
 | |
|       expect(result.runs.length).toBe(1);
 | |
|       expect(result.runs[0].test()).toBe(t.tests()[0]);
 | |
|       expect(result.runs[0].result()).toBe('ok');
 | |
|     });
 | |
|     it('should run a failed focused test', async() => {
 | |
|       const t = new Runner();
 | |
|       let run = false;
 | |
|       t.it.only.fail('uno', () => {
 | |
|         run = true; throw new Error('failure');
 | |
|       });
 | |
|       expect(t.focusedTests().length).toBe(1);
 | |
|       expect(t.tests()[0].expectation()).toBe(t.Expectations.Fail);
 | |
|       const result = await t.run();
 | |
|       expect(run).toBe(true);
 | |
|       expect(result.runs.length).toBe(1);
 | |
|       expect(result.runs[0].test()).toBe(t.tests()[0]);
 | |
|       expect(result.runs[0].result()).toBe('failed');
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('TestRunner.describe', () => {
 | |
|     it('should declare a suite', async() => {
 | |
|       const t = new Runner();
 | |
|       t.describe('suite', () => {
 | |
|         t.it('uno', () => {});
 | |
|       });
 | |
|       expect(t.tests().length).toBe(1);
 | |
|       const test = t.tests()[0];
 | |
|       expect(test.name()).toBe('uno');
 | |
|       expect(test.fullName()).toBe('suite uno');
 | |
|       expect(test.skipped()).toBe(false);
 | |
|       expect(test.suite().name()).toBe('suite');
 | |
|       expect(test.suite().fullName()).toBe('suite');
 | |
|       expect(test.suite().skipped()).toBe(false);
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('TestRunner.xdescribe', () => {
 | |
|     it('should declare a skipped suite', async() => {
 | |
|       const t = new Runner();
 | |
|       t.xdescribe('suite', () => {
 | |
|         t.it('uno', () => {});
 | |
|       });
 | |
|       expect(t.tests().length).toBe(1);
 | |
|       const test = t.tests()[0];
 | |
|       expect(test.skipped()).toBe(false);
 | |
|       expect(test.suite().skipped()).toBe(true);
 | |
|     });
 | |
|     it('focused tests inside a skipped suite are not run', async() => {
 | |
|       const t = new Runner();
 | |
|       let run = false;
 | |
|       t.xdescribe('suite', () => {
 | |
|         t.fit('uno', () => { run = true; });
 | |
|       });
 | |
|       const result = await t.run();
 | |
|       expect(run).toBe(false);
 | |
|       expect(result.runs.length).toBe(1);
 | |
|       expect(result.runs[0].test()).toBe(t.tests()[0]);
 | |
|       expect(result.runs[0].result()).toBe('skipped');
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('TestRunner.fdescribe', () => {
 | |
|     it('should declare a focused suite', async() => {
 | |
|       const t = new Runner();
 | |
|       t.fdescribe('suite', () => {
 | |
|         t.it('uno', () => {});
 | |
|       });
 | |
|       expect(t.tests().length).toBe(1);
 | |
|       const test = t.tests()[0];
 | |
|       expect(test.skipped()).toBe(false);
 | |
|       expect(t.focusedSuites()[0]).toBe(test.suite());
 | |
|       expect(test.suite().skipped()).toBe(false);
 | |
|     });
 | |
|     it('skipped tests inside a focused suite should not be run', async() => {
 | |
|       const t = new Runner();
 | |
|       t.fdescribe('suite', () => {
 | |
|         t.xit('uno', () => {});
 | |
|       });
 | |
|       const result = await t.run();
 | |
|       expect(result.runs.length).toBe(1);
 | |
|       expect(result.runs[0].test()).toBe(t.tests()[0]);
 | |
|       expect(result.runs[0].result()).toBe('skipped');
 | |
|     });
 | |
|     it('should run all "run" tests inside a focused suite', async() => {
 | |
|       const log = [];
 | |
|       const t = new Runner();
 | |
|       t.it('uno', () => log.push(1));
 | |
|       t.fdescribe('suite1', () => {
 | |
|         t.it('dos', () => log.push(2));
 | |
|         t.it('tres', () => log.push(3));
 | |
|       });
 | |
|       t.it('cuatro', () => log.push(4));
 | |
|       await t.run();
 | |
|       expect(log.join()).toBe('2,3');
 | |
|     });
 | |
|     it('should run only "focus" tests inside a focused suite', async() => {
 | |
|       const log = [];
 | |
|       const t = new Runner();
 | |
|       t.it('uno', () => log.push(1));
 | |
|       t.fdescribe('suite1', () => {
 | |
|         t.fit('dos', () => log.push(2));
 | |
|         t.it('tres', () => log.push(3));
 | |
|       });
 | |
|       t.it('cuatro', () => log.push(4));
 | |
|       await t.run();
 | |
|       expect(log.join()).toBe('2');
 | |
|     });
 | |
|     it('should run both "run" tests in focused suite and non-descendant focus tests', async() => {
 | |
|       const log = [];
 | |
|       const t = new Runner();
 | |
|       t.it('uno', () => log.push(1));
 | |
|       t.fdescribe('suite1', () => {
 | |
|         t.it('dos', () => log.push(2));
 | |
|         t.it('tres', () => log.push(3));
 | |
|       });
 | |
|       t.fit('cuatro', () => log.push(4));
 | |
|       await t.run();
 | |
|       expect(log.join()).toBe('2,3,4');
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('TestRunner attributes', () => {
 | |
|     it('should work', async() => {
 | |
|       const t = new Runner({timeout: 123});
 | |
|       const log = [];
 | |
| 
 | |
|       t._collector.addTestModifier('foo', (t, ...args) => {
 | |
|         log.push('foo');
 | |
| 
 | |
|         expect(t.skipped()).toBe(false);
 | |
|         expect(t.Expectations.Ok).toBeTruthy();
 | |
|         expect(t.Expectations.Fail).toBeTruthy();
 | |
|         expect(t.expectation()).toBe(t.Expectations.Ok);
 | |
|         expect(t.timeout()).toBe(123);
 | |
| 
 | |
|         expect(args.length).toBe(2);
 | |
|         expect(args[0]).toBe('uno');
 | |
|         expect(args[1]).toBe('dos');
 | |
| 
 | |
|         t.setExpectation(t.Expectations.Fail);
 | |
|         t.setTimeout(234);
 | |
|       });
 | |
| 
 | |
|       t._collector.addTestAttribute('bar', t => {
 | |
|         log.push('bar');
 | |
|         t.setSkipped(true);
 | |
|         expect(t.skipped()).toBe(true);
 | |
|         expect(t.expectation()).toBe(t.Expectations.Fail);
 | |
|         expect(t.timeout()).toBe(234);
 | |
|       });
 | |
| 
 | |
|       t.it.foo('uno', 'dos').bar('test', () => { });
 | |
|       expect(log).toEqual(['foo', 'bar']);
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('TestRunner hooks', () => {
 | |
|     it('should run all hooks in proper order', async() => {
 | |
|       const log = [];
 | |
|       const t = new Runner();
 | |
|       const e = new Environment('env');
 | |
|       e.beforeAll(() => log.push('env:beforeAll'));
 | |
|       e.afterAll(() => log.push('env:afterAll'));
 | |
|       e.beforeEach(() => log.push('env:beforeEach'));
 | |
|       e.afterEach(() => log.push('env:afterEach'));
 | |
|       const e2 = new Environment('env2', e);
 | |
|       e2.beforeAll(() => log.push('env2:beforeAll'));
 | |
|       e2.afterAll(() => log.push('env2:afterAll'));
 | |
|       t.beforeAll(() => log.push('root:beforeAll'));
 | |
|       t.beforeEach(() => log.push('root:beforeEach1'));
 | |
|       t.beforeEach(() => log.push('root:beforeEach2'));
 | |
|       t.it('uno', () => log.push('test #1'));
 | |
|       t.describe('suite1', () => {
 | |
|         t.beforeAll(() => log.push('suite:beforeAll1'));
 | |
|         t.beforeAll(() => log.push('suite:beforeAll2'));
 | |
|         t.beforeEach(() => log.push('suite:beforeEach'));
 | |
|         t.it('dos', () => log.push('test #2'));
 | |
|         t.tests()[t.tests().length - 1].environment().beforeEach(() => log.push('test:before1'));
 | |
|         t.tests()[t.tests().length - 1].environment().beforeEach(() => log.push('test:before2'));
 | |
|         t.tests()[t.tests().length - 1].environment().afterEach(() => log.push('test:after1'));
 | |
|         t.tests()[t.tests().length - 1].environment().afterEach(() => log.push('test:after2'));
 | |
|         t.it('tres', () => log.push('test #3'));
 | |
|         t.tests()[t.tests().length - 1].environment().beforeEach(() => log.push('test:before1'));
 | |
|         t.tests()[t.tests().length - 1].environment().beforeEach(() => log.push('test:before2'));
 | |
|         t.tests()[t.tests().length - 1].environment().afterEach(() => log.push('test:after1'));
 | |
|         t.tests()[t.tests().length - 1].environment().afterEach(() => log.push('test:after2'));
 | |
|         t.afterEach(() => log.push('suite:afterEach1'));
 | |
|         t.afterEach(() => log.push('suite:afterEach2'));
 | |
|         t.afterAll(() => log.push('suite:afterAll'));
 | |
|       });
 | |
|       t.it('cuatro', () => log.push('test #4'));
 | |
|       t.tests()[t.tests().length - 1].addEnvironment(e2);
 | |
|       t.describe('no hooks suite', () => {
 | |
|         t.describe('suite2', () => {
 | |
|           t.beforeAll(() => log.push('suite2:beforeAll'));
 | |
|           t.afterAll(() => log.push('suite2:afterAll'));
 | |
|           t.describe('no hooks suite 2', () => {
 | |
|             t.it('cinco', () => log.push('test #5'));
 | |
|           });
 | |
|         });
 | |
|       });
 | |
|       t.suites()[t.suites().length - 1].addEnvironment(e2);
 | |
|       t.afterEach(() => log.push('root:afterEach'));
 | |
|       t.afterAll(() => log.push('root:afterAll1'));
 | |
|       t.afterAll(() => log.push('root:afterAll2'));
 | |
|       await t.run();
 | |
|       expect(log).toEqual([
 | |
|         'root:beforeAll',
 | |
|         'root:beforeEach1',
 | |
|         'root:beforeEach2',
 | |
|         'test #1',
 | |
|         'root:afterEach',
 | |
| 
 | |
|         'suite:beforeAll1',
 | |
|         'suite:beforeAll2',
 | |
| 
 | |
|         'root:beforeEach1',
 | |
|         'root:beforeEach2',
 | |
|         'suite:beforeEach',
 | |
|         'test:before1',
 | |
|         'test:before2',
 | |
|         'test #2',
 | |
|         'test:after1',
 | |
|         'test:after2',
 | |
|         'suite:afterEach1',
 | |
|         'suite:afterEach2',
 | |
|         'root:afterEach',
 | |
| 
 | |
|         'root:beforeEach1',
 | |
|         'root:beforeEach2',
 | |
|         'suite:beforeEach',
 | |
|         'test:before1',
 | |
|         'test:before2',
 | |
|         'test #3',
 | |
|         'test:after1',
 | |
|         'test:after2',
 | |
|         'suite:afterEach1',
 | |
|         'suite:afterEach2',
 | |
|         'root:afterEach',
 | |
| 
 | |
|         'suite:afterAll',
 | |
| 
 | |
|         'env:beforeAll',
 | |
|         'env2:beforeAll',
 | |
| 
 | |
|         'root:beforeEach1',
 | |
|         'root:beforeEach2',
 | |
|         'env:beforeEach',
 | |
|         'test #4',
 | |
|         'env:afterEach',
 | |
|         'root:afterEach',
 | |
| 
 | |
|         'suite2:beforeAll',
 | |
|         'root:beforeEach1',
 | |
|         'root:beforeEach2',
 | |
|         'env:beforeEach',
 | |
|         'test #5',
 | |
|         'env:afterEach',
 | |
|         'root:afterEach',
 | |
|         'suite2:afterAll',
 | |
| 
 | |
|         'env2:afterAll',
 | |
|         'env:afterAll',
 | |
| 
 | |
|         'root:afterAll1',
 | |
|         'root:afterAll2',
 | |
|       ]);
 | |
|     });
 | |
|     it('should remove environment', async() => {
 | |
|       const log = [];
 | |
|       const t = new Runner();
 | |
|       const e = new Environment('env');
 | |
|       e.beforeAll(() => log.push('env:beforeAll'));
 | |
|       e.afterAll(() => log.push('env:afterAll'));
 | |
|       e.beforeEach(() => log.push('env:beforeEach'));
 | |
|       e.afterEach(() => log.push('env:afterEach'));
 | |
|       const e2 = new Environment('env2');
 | |
|       e2.beforeAll(() => log.push('env2:beforeAll'));
 | |
|       e2.afterAll(() => log.push('env2:afterAll'));
 | |
|       e2.beforeEach(() => log.push('env2:beforeEach'));
 | |
|       e2.afterEach(() => log.push('env2:afterEach'));
 | |
|       t.it('uno', () => log.push('test #1'));
 | |
|       t.tests()[0].addEnvironment(e).addEnvironment(e2).removeEnvironment(e);
 | |
|       await t.run();
 | |
|       expect(log).toEqual([
 | |
|         'env2:beforeAll',
 | |
|         'env2:beforeEach',
 | |
|         'test #1',
 | |
|         'env2:afterEach',
 | |
|         'env2:afterAll',
 | |
|       ]);
 | |
|     });
 | |
|     it('should have the same state object in hooks and test', async() => {
 | |
|       const states = [];
 | |
|       const t = new Runner();
 | |
|       t.beforeEach(state => states.push(state));
 | |
|       t.afterEach(state => states.push(state));
 | |
|       t.beforeAll(state => states.push(state));
 | |
|       t.afterAll(state => states.push(state));
 | |
|       t.it('uno', state => states.push(state));
 | |
|       await t.run();
 | |
|       expect(states.length).toBe(5);
 | |
|       for (let i = 1; i < states.length; ++i)
 | |
|         expect(states[i]).toBe(states[0]);
 | |
|     });
 | |
|     it('should unwind hooks properly when terminated', async() => {
 | |
|       const log = [];
 | |
|       const t = new Runner({timeout: 10000});
 | |
|       t.beforeAll(() => log.push('beforeAll'));
 | |
|       t.beforeEach(() => log.push('beforeEach'));
 | |
|       t.afterEach(() => log.push('afterEach'));
 | |
|       t.afterAll(() => log.push('afterAll'));
 | |
|       t.it('uno', () => {
 | |
|         log.push('terminating...');
 | |
|         t.terminate();
 | |
|       });
 | |
|       await t.run();
 | |
| 
 | |
|       expect(log).toEqual([
 | |
|         'beforeAll',
 | |
|         'beforeEach',
 | |
|         'terminating...',
 | |
|         'afterEach',
 | |
|         'afterAll',
 | |
|       ]);
 | |
|     });
 | |
|     it('should report as terminated even when hook crashes', async() => {
 | |
|       const t = new Runner({timeout: 10000});
 | |
|       t.afterEach(() => { throw new Error('crash!'); });
 | |
|       t.it('uno', () => { t.terminate(); });
 | |
|       const result = await t.run();
 | |
|       expect(result.runs[0].result()).toBe('terminated');
 | |
|     });
 | |
|     it('should report as terminated when terminated during hook', async() => {
 | |
|       const t = new Runner({timeout: 10000});
 | |
|       t.afterEach(() => { t.terminate(); });
 | |
|       t.it('uno', () => { });
 | |
|       const result = await t.run();
 | |
|       expect(result.runs[0].result()).toBe('terminated');
 | |
|     });
 | |
|     it('should unwind hooks properly when crashed', async() => {
 | |
|       const log = [];
 | |
|       const t = new Runner({timeout: 10000});
 | |
|       t.beforeAll(() => log.push('root beforeAll'));
 | |
|       t.beforeEach(() => log.push('root beforeEach'));
 | |
|       t.describe('suite', () => {
 | |
|         t.beforeAll(() => log.push('suite beforeAll'));
 | |
|         t.beforeEach(() => log.push('suite beforeEach'));
 | |
|         t.it('uno', () => log.push('uno'));
 | |
|         t.afterEach(() => {
 | |
|           log.push('CRASH >> suite afterEach');
 | |
|           throw new Error('crash!');
 | |
|         });
 | |
|         t.afterAll(() => log.push('suite afterAll'));
 | |
|       });
 | |
|       t.afterEach(() => log.push('root afterEach'));
 | |
|       t.afterAll(() => log.push('root afterAll'));
 | |
|       await t.run();
 | |
| 
 | |
|       expect(log).toEqual([
 | |
|         'root beforeAll',
 | |
|         'suite beforeAll',
 | |
|         'root beforeEach',
 | |
|         'suite beforeEach',
 | |
|         'uno',
 | |
|         'CRASH >> suite afterEach',
 | |
|         'root afterEach',
 | |
|         'suite afterAll',
 | |
|         'root afterAll'
 | |
|       ]);
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('TestRunner.run', () => {
 | |
|     it('should run a test', async() => {
 | |
|       const t = new Runner();
 | |
|       let ran = false;
 | |
|       t.it('uno', () => ran = true);
 | |
|       await t.run();
 | |
|       expect(ran).toBe(true);
 | |
|     });
 | |
|     it('should handle repeat', async() => {
 | |
|       const t = new Runner();
 | |
|       let suite = 0;
 | |
|       let test = 0;
 | |
|       let beforeAll = 0;
 | |
|       let beforeEach = 0;
 | |
|       t.describe.repeat(2)('suite', () => {
 | |
|         suite++;
 | |
|         t.beforeAll(() => beforeAll++);
 | |
|         t.beforeEach(() => beforeEach++);
 | |
|         t.it.repeat(3)('uno', () => test++);
 | |
|       });
 | |
|       await t.run();
 | |
|       expect(suite).toBe(1);
 | |
|       expect(beforeAll).toBe(1);
 | |
|       expect(beforeEach).toBe(6);
 | |
|       expect(test).toBe(6);
 | |
|     });
 | |
|     it('should repeat without breaking test order', async() => {
 | |
|       const t = new Runner();
 | |
|       const log = [];
 | |
|       t.describe.repeat(2)('suite', () => {
 | |
|         t.it('uno', () => log.push(1));
 | |
|         t.it.repeat(2)('dos', () => log.push(2));
 | |
|       });
 | |
|       t.it('tres', () => log.push(3));
 | |
|       await t.run();
 | |
|       expect(log.join()).toBe('1,2,2,1,2,2,3');
 | |
|     });
 | |
|     it('should run tests if some fail', async() => {
 | |
|       const t = new Runner();
 | |
|       const log = [];
 | |
|       t.it('uno', () => log.push(1));
 | |
|       t.it('dos', () => { throw new Error('bad'); });
 | |
|       t.it('tres', () => log.push(3));
 | |
|       await t.run();
 | |
|       expect(log.join()).toBe('1,3');
 | |
|     });
 | |
|     it('should run tests if some timeout', async() => {
 | |
|       const t = new Runner({timeout: 1});
 | |
|       const log = [];
 | |
|       t.it('uno', () => log.push(1));
 | |
|       t.it('dos', async() => new Promise(() => {}));
 | |
|       t.it('tres', () => log.push(3));
 | |
|       await t.run();
 | |
|       expect(log.join()).toBe('1,3');
 | |
|     });
 | |
|     it('should break on first failure if configured so', async() => {
 | |
|       const log = [];
 | |
|       const t = new Runner({breakOnFailure: true});
 | |
|       t.it('test#1', () => log.push('test#1'));
 | |
|       t.it('test#2', () => log.push('test#2'));
 | |
|       t.it('test#3', () => { throw new Error('crash'); });
 | |
|       t.it('test#4', () => log.push('test#4'));
 | |
|       await t.run();
 | |
|       expect(log).toEqual([
 | |
|         'test#1',
 | |
|         'test#2',
 | |
|       ]);
 | |
|     });
 | |
|     it('should pass a state and a test as a test parameters', async() => {
 | |
|       const log = [];
 | |
|       const t = new Runner();
 | |
|       t.beforeEach(state => state.FOO = 42);
 | |
|       t.it('uno', (state, testRun) => {
 | |
|         log.push('state.FOO=' + state.FOO);
 | |
|         log.push('test=' + testRun.test().name());
 | |
|       });
 | |
|       await t.run();
 | |
|       expect(log.join()).toBe('state.FOO=42,test=uno');
 | |
|     });
 | |
|     it('should run async test', async() => {
 | |
|       const t = new Runner();
 | |
|       let ran = false;
 | |
|       t.it('uno', async() => {
 | |
|         await new Promise(x => setTimeout(x, 10));
 | |
|         ran = true;
 | |
|       });
 | |
|       await t.run();
 | |
|       expect(ran).toBe(true);
 | |
|     });
 | |
|     it('should run async tests in order of their declaration', async() => {
 | |
|       const log = [];
 | |
|       const t = new Runner();
 | |
|       t.it('uno', async() => {
 | |
|         await new Promise(x => setTimeout(x, 30));
 | |
|         log.push(1);
 | |
|       });
 | |
|       t.it('dos', async() => {
 | |
|         await new Promise(x => setTimeout(x, 20));
 | |
|         log.push(2);
 | |
|       });
 | |
|       t.it('tres', async() => {
 | |
|         await new Promise(x => setTimeout(x, 10));
 | |
|         log.push(3);
 | |
|       });
 | |
|       await t.run();
 | |
|       expect(log.join()).toBe('1,2,3');
 | |
|     });
 | |
|     it('should run multiple tests', async() => {
 | |
|       const log = [];
 | |
|       const t = new Runner();
 | |
|       t.it('uno', () => log.push(1));
 | |
|       t.it('dos', () => log.push(2));
 | |
|       await t.run();
 | |
|       expect(log.join()).toBe('1,2');
 | |
|     });
 | |
|     it('should NOT run a skipped test', async() => {
 | |
|       const t = new Runner();
 | |
|       let ran = false;
 | |
|       t.xit('uno', () => ran = true);
 | |
|       await t.run();
 | |
|       expect(ran).toBe(false);
 | |
|     });
 | |
|     it('should run ONLY non-skipped tests', async() => {
 | |
|       const log = [];
 | |
|       const t = new Runner();
 | |
|       t.it('uno', () => log.push(1));
 | |
|       t.xit('dos', () => log.push(2));
 | |
|       t.it('tres', () => log.push(3));
 | |
|       await t.run();
 | |
|       expect(log.join()).toBe('1,3');
 | |
|     });
 | |
|     it('should run ONLY focused tests', async() => {
 | |
|       const log = [];
 | |
|       const t = new Runner();
 | |
|       t.it('uno', () => log.push(1));
 | |
|       t.xit('dos', () => log.push(2));
 | |
|       t.fit('tres', () => log.push(3));
 | |
|       await t.run();
 | |
|       expect(log.join()).toBe('3');
 | |
|     });
 | |
|     it('should run tests in order of their declaration', async() => {
 | |
|       const log = [];
 | |
|       const t = new Runner();
 | |
|       t.it('uno', () => log.push(1));
 | |
|       t.describe('suite1', () => {
 | |
|         t.it('dos', () => log.push(2));
 | |
|         t.it('tres', () => log.push(3));
 | |
|       });
 | |
|       t.it('cuatro', () => log.push(4));
 | |
|       await t.run();
 | |
|       expect(log.join()).toBe('1,2,3,4');
 | |
|     });
 | |
|     it('should respect total timeout', async() => {
 | |
|       const t = new Runner({timeout: 10000, totalTimeout: 1});
 | |
|       t.it('uno', async () => { await new Promise(() => {}); });
 | |
|       const result = await t.run();
 | |
|       expect(result.runs[0].result()).toBe('terminated');
 | |
|       expect(result.message).toContain('Total timeout');
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('TestRunner.run result', () => {
 | |
|     it('should return OK if all tests pass', async() => {
 | |
|       const t = new Runner();
 | |
|       t.it('uno', () => {});
 | |
|       const result = await t.run();
 | |
|       expect(result.result).toBe('ok');
 | |
|     });
 | |
|     it('should return FAIL if at least one test fails', async() => {
 | |
|       const t = new Runner();
 | |
|       t.it('uno', () => { throw new Error('woof'); });
 | |
|       const result = await t.run();
 | |
|       expect(result.result).toBe('failed');
 | |
|     });
 | |
|     it('should return FAIL if at least one test times out', async() => {
 | |
|       const t = new Runner({timeout: 1});
 | |
|       t.it('uno', async() => new Promise(() => {}));
 | |
|       const result = await t.run();
 | |
|       expect(result.result).toBe('failed');
 | |
|     });
 | |
|     it('should return TERMINATED if it was terminated', async() => {
 | |
|       const t = new Runner({timeout: 1000000});
 | |
|       t.it('uno', async() => new Promise(() => {}));
 | |
|       const [result] = await Promise.all([
 | |
|         t.run(),
 | |
|         t.terminate(),
 | |
|       ]);
 | |
|       expect(result.result).toBe('terminated');
 | |
|     });
 | |
|     it('should return CRASHED if it crashed', async() => {
 | |
|       const t = new Runner({timeout: 1});
 | |
|       t.it('uno', async() => new Promise(() => {}));
 | |
|       t.afterAll(() => { throw new Error('woof');});
 | |
|       const result = await t.run();
 | |
|       expect(result.result).toBe('crashed');
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('TestRunner parallel', () => {
 | |
|     it('should run tests in parallel', async() => {
 | |
|       const log = [];
 | |
|       const t = new Runner({parallel: 2});
 | |
|       t.it('uno', async state => {
 | |
|         log.push(`Worker #${state.parallelIndex} Starting: UNO`);
 | |
|         await Promise.resolve();
 | |
|         log.push(`Worker #${state.parallelIndex} Ending: UNO`);
 | |
|       });
 | |
|       t.it('dos', async state => {
 | |
|         log.push(`Worker #${state.parallelIndex} Starting: DOS`);
 | |
|         await Promise.resolve();
 | |
|         log.push(`Worker #${state.parallelIndex} Ending: DOS`);
 | |
|       });
 | |
|       await t.run();
 | |
|       expect(log).toEqual([
 | |
|         'Worker #0 Starting: UNO',
 | |
|         'Worker #1 Starting: DOS',
 | |
|         'Worker #0 Ending: UNO',
 | |
|         'Worker #1 Ending: DOS',
 | |
|       ]);
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('TestRunner.hasFocusedTestsOrSuites', () => {
 | |
|     it('should work', () => {
 | |
|       const t = new Runner();
 | |
|       t.it('uno', () => {});
 | |
|       expect(t._filter.hasFocusedTestsOrSuites()).toBe(false);
 | |
|     });
 | |
|     it('should work #2', () => {
 | |
|       const t = new Runner();
 | |
|       t.fit('uno', () => {});
 | |
|       expect(t._filter.hasFocusedTestsOrSuites()).toBe(true);
 | |
|     });
 | |
|     it('should work #3', () => {
 | |
|       const t = new Runner();
 | |
|       t.describe('suite #1', () => {
 | |
|         t.fdescribe('suite #2', () => {
 | |
|           t.describe('suite #3', () => {
 | |
|             t.it('uno', () => {});
 | |
|           });
 | |
|         });
 | |
|       });
 | |
|       expect(t._filter.hasFocusedTestsOrSuites()).toBe(true);
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('TestRunner result', () => {
 | |
|     it('should work for both throwing and timeouting tests', async() => {
 | |
|       const t = new Runner({timeout: 1});
 | |
|       t.it('uno', () => { throw new Error('boo');});
 | |
|       t.it('dos', () => new Promise(() => {}));
 | |
|       const result = await t.run();
 | |
|       expect(result.runs[0].result()).toBe('failed');
 | |
|       expect(result.runs[1].result()).toBe('timedout');
 | |
|     });
 | |
|     it('should report crashed tests', async() => {
 | |
|       const t = new Runner();
 | |
|       t.beforeEach(() => { throw new Error('woof');});
 | |
|       t.it('uno', () => {});
 | |
|       const result = await t.run();
 | |
|       expect(result.runs[0].result()).toBe('crashed');
 | |
|     });
 | |
|     it('skipped should work for both throwing and timeouting tests', async() => {
 | |
|       const t = new Runner({timeout: 1});
 | |
|       t.xit('uno', () => { throw new Error('boo');});
 | |
|       const result = await t.run();
 | |
|       expect(result.runs[0].result()).toBe('skipped');
 | |
|     });
 | |
|     it('should return OK', async() => {
 | |
|       const t = new Runner();
 | |
|       t.it('uno', () => {});
 | |
|       const result = await t.run();
 | |
|       expect(result.runs[0].result()).toBe('ok');
 | |
|     });
 | |
|     it('should return TIMEDOUT', async() => {
 | |
|       const t = new Runner({timeout: 1});
 | |
|       t.it('uno', async() => new Promise(() => {}));
 | |
|       const result = await t.run();
 | |
|       expect(result.runs[0].result()).toBe('timedout');
 | |
|     });
 | |
|     it('should return SKIPPED', async() => {
 | |
|       const t = new Runner();
 | |
|       t.xit('uno', () => {});
 | |
|       const result = await t.run();
 | |
|       expect(result.runs[0].result()).toBe('skipped');
 | |
|     });
 | |
|     it('should return FAILED', async() => {
 | |
|       const t = new Runner();
 | |
|       t.it('uno', async() => Promise.reject('woof'));
 | |
|       const result = await t.run();
 | |
|       expect(result.runs[0].result()).toBe('failed');
 | |
|     });
 | |
|     it('should return TERMINATED', async() => {
 | |
|       const t = new Runner();
 | |
|       t.it('uno', async() => t.terminate());
 | |
|       const result = await t.run();
 | |
|       expect(result.runs[0].result()).toBe('terminated');
 | |
|     });
 | |
|     it('should return CRASHED', async() => {
 | |
|       const t = new Runner();
 | |
|       t.it('uno', () => {});
 | |
|       t.afterEach(() => {throw new Error('foo');});
 | |
|       const result = await t.run();
 | |
|       expect(result.runs[0].result()).toBe('crashed');
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('TestRunner delegate', () => {
 | |
|     it('should call delegate methods in proper order', async() => {
 | |
|       const log = [];
 | |
|       const t = new Runner({
 | |
|         onStarted: () => log.push('E:started'),
 | |
|         onTestRunStarted: () => log.push('E:teststarted'),
 | |
|         onTestRunFinished: () => log.push('E:testfinished'),
 | |
|         onFinished: () => log.push('E:finished'),
 | |
|       });
 | |
|       t.beforeAll(() => log.push('beforeAll'));
 | |
|       t.beforeEach(() => log.push('beforeEach'));
 | |
|       t.it('test#1', () => log.push('test#1'));
 | |
|       t.afterEach(() => log.push('afterEach'));
 | |
|       t.afterAll(() => log.push('afterAll'));
 | |
|       await t.run();
 | |
|       expect(log).toEqual([
 | |
|         'E:started',
 | |
|         'beforeAll',
 | |
|         'E:teststarted',
 | |
|         'beforeEach',
 | |
|         'test#1',
 | |
|         'afterEach',
 | |
|         'E:testfinished',
 | |
|         'afterAll',
 | |
|         'E:finished',
 | |
|       ]);
 | |
|     });
 | |
|     it('should call onFinished with result', async() => {
 | |
|       let onFinished;
 | |
|       const finishedPromise = new Promise(f => onFinished = f);
 | |
|       const [result] = await Promise.all([
 | |
|         finishedPromise,
 | |
|         new TestRunner().run([], { onFinished }),
 | |
|       ]);
 | |
|       expect(result.result).toBe('ok');
 | |
|     });
 | |
|     it('should crash when onStarted throws', async() => {
 | |
|       const t = new Runner({
 | |
|         onStarted: () => { throw 42; },
 | |
|       });
 | |
|       const result = await t.run();
 | |
|       expect(result.ok()).toBe(false);
 | |
|       expect(result.message).toBe('INTERNAL ERROR: 42');
 | |
|     });
 | |
|     it('should crash when onFinished throws', async() => {
 | |
|       const t = new Runner({
 | |
|         onFinished: () => { throw new Error('42'); },
 | |
|       });
 | |
|       const result = await t.run();
 | |
|       expect(result.ok()).toBe(false);
 | |
|       expect(result.message).toBe('INTERNAL ERROR');
 | |
|       expect(result.result).toBe('crashed');
 | |
|     });
 | |
|   });
 | |
| };
 | |
| 
 | 
