Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tests using ComponentTester.manuallyHandleLifecycle() can cause unrelated tests to fail #95

Open
that-crazy-fox opened this issue Nov 12, 2019 · 0 comments

Comments

@that-crazy-fox
Copy link

I'm submitting a bug report

  • Library Version:
    1.0.0

Please tell us about your environment:

  • Operating System:
    Windows 10

  • Node Version:
    10.16.0

  • NPM Version:
    6.9.0
  • JSPM OR Webpack AND Version
    JSPM 0.16.54
  • Browser:
    Chrome 78

  • Language:
    ESNext

Current behavior:
When using ComponentTester with .manuallyHandleLifecycle() (as shown in the documentation), if the test does not call .bind() or .attached(), it can cause failures for subsequent tests. This seems to be caused by ComponentTester's _prepareLifecycle() method, which alters the View prototype's .bind and .attached properties. If the .bind and .attached methods of ComponentTester are not called, View.prototype will never be restored to its original behavior, causing subsequent tests to fail if they depend on the .bind and .attached methods of View.

Steps to reproduce

  1. Create my-component.js and my-component.html
//my-component.js
export class MyComponentCustomElement {
	constructor() {
		this.myProperty = "created";
	}

	bind() {
		this.myProperty = "bound";
	}

	attached() {
		this.myProperty = "attached";
	}
}
<!--my-component.html-->
<template>
</template>
  1. Create a test suite for my-component (I'm using Jasmine here)
//my-component.spec.js
import { StageComponent } from 'aurelia-testing';
import { bootstrap } from 'aurelia-bootstrapper';

describe('My Component', () => {
	let componentTester;

	beforeEach(() => {
		componentTester = StageComponent
			.withResources('my-component')
			.inView('<my-component></my-component>')
			.boundTo({});
	});

	afterEach(() => {
		componentTester.dispose();
	});

	it('should manually handle partial lifecycles', done => {
		componentTester.manuallyHandleLifecycle().create(bootstrap)
			.then(() => {
				expect(componentTester.viewModel.myProperty).toBe('created');
			})
			.then(() => componentTester.bind())
			.then(() => {
				expect(componentTester.viewModel.myProperty).toBe('bound');
			})
			.then(done)
			.catch(reason => {
				fail(reason);
				done();
			});
	});

	it('should manually handle full lifecycles', done => {
		componentTester.manuallyHandleLifecycle().create(bootstrap)
			.then(() => componentTester.bind())
			.then(() => componentTester.attached())
			.then(() => {
				expect(componentTester.viewModel.myProperty).toBe("attached");
			})
			.then(done)
			.catch(reason => {
				fail(reason);
				done();
			});
	});
});
  1. Run the tests. The first test will pass and the second test will fail. If the test runner executes tests in a random order, and the second test is executed first, both tests will pass.

This behavior is also observed when a lifecycle Promise is rejected, as this causes the rest of the Promise chain to be skipped.

Expected/desired behavior:

Both tests should pass, regardless of their execution order. When ComponentTester.dispose() is called, I expect all changes it made to the environment to be reset. I expect View objects to have their original function. Additionally, when a test fails due to a rejected Promise, I expect other tests to be unaffected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant