# jest-class-spec

> Write tests using a class. The constructur works as beforeEach, meaning a new instance is created for every test method. Methods starting with `should` are seen as test methods (it/test in jest). This allows tests to access variables defined in the setup

Latest version **0.1.1** (published 2020-12-01) · MIT license · 0 weekly downloads

## Install

```sh
npm install jest-class-spec
pnpm add jest-class-spec
yarn add jest-class-spec
bun add jest-class-spec
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support; pre 1.0.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 0.1.1 |
| Published | 2020-12-01 |
| First published | 2020-11-30 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 0 |
| Unpacked size | 6.3 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 3 |
| Author | Torkel Ödegaard |
| Maintainers | torkelo |

## Links

- npm: https://www.npmjs.com/package/jest-class-spec
- Repository: https://github.com/torkelo/jest-class-spec
- Homepage: https://github.com/torkelo/jest-class-spec#readme
- Issues: https://github.com/torkelo/jest-class-spec/issues
- npm.io page: https://npm.io/package/jest-class-spec

## Recent versions

- 0.1.1 (latest) — 2020-12-01
- 0.1.0 — 2020-11-30

## README

# Jest class spec

Write tests using a class. The constructur works as beforeEach, meaning a new instance is created for every test method. Methods starting with `should` are seen as test methods (it/test in jest). This
allows tests to access variables defined in the setup block.

```typescript
runSpec(
  class MySpecName {
    constext = {
      user: { firstName: 'Torkel', lastName: 'Grafana' },
      auth: { isLoggedIn: true }
    };

    service = new OrderService(this.context, { logging: true })

    'should be able to access dynamic types with full intellisense and type check'() {
      expect(this.context.auth.isLoggedIn).toBe(true);
    }

    'should run each test method in a separate instance'() {
      const order = this.service.createOrder();
      expect(order.user.firstName).toBe(this.context.user.firstName);
    }
  }
);

```

**Wait is this not the same as this?**

```typescript
describe("Order service", () => {
  constext = {
    user: { firstName: 'Torkel', lastName: 'Grafana' },
    auth: { isLoggedIn: true }
  };

  service = new MyService(this.context, { logging: true })

  it('should be able to access dynamic types with full intellisense and type check', () => {
    expect(this.context.auth.isLoggedIn).toBe(true);
  }

  it('should run each test method in a separate instance', () => {
    const newOrder = this.service.createOrder();
    expect(order.user.firstName).toBe(this.context.user.firstName);
  });
})
```

No this is not the same. In the above example context & service variables will only be created once and shared in both tests, so a side-effect / state modification in the first test can impact the next. That
is why setup code like the above is seen as bad and why using a beforeEach block is better.


## Motivation / Why?


The current model for beforeEach is deeply flawed as you cannot define variables inside the beforeEach function that are accessible from the test. You have to define nullable/undefined variables in an outer scope.
This is especially problematic for dynamic/inferred types or typescript with strict null checks. You cannot create const variables and have to resort to tricks like this:

```typescript
let aVar: SomeType | undefined;

beforeEach( ()=> {
   aVar = new SomeType;
   // This variable is not accessible by test and would require a type new definition for an outer variable :(
   const context = {
       prop1: 'hello';
       prop2: true,
   }
   // This is not accessible
   const service = new MyService(context);
});

test("A Test", ()=> {
    // Argh! I want to access the service and and the context variables :(
});
```

## More examples

If you have `experimentalDecorators` enabled in your tsconfig you can use runSpec as a decorator

```typescript
@runSpec
export class Given_login_service_with_anonymous_user {
  const user = new User({isAnonymous: true})
  const loginService = new LoginService(this.user)

  'Should deny access'() {
    expect(loginService.hasAccessToAdmin()).toBe(false)
  }
}
```

## Try it out

NPM

```
npm install jest-spec-class --save-dev
```

Yarn
```
yarn add --dev jest-spec-class
```

Then from your code just import it like

```typescript
import { runSpec } from '../src/index'
```

---
_Source: https://npm.io/package/jest-class-spec · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
