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

Jest support #129

Closed
fernandopasik opened this issue Oct 4, 2017 · 8 comments
Closed

Jest support #129

fernandopasik opened this issue Oct 4, 2017 · 8 comments

Comments

@fernandopasik
Copy link

Since there are jasmine matchers do you know if there is a way to use them with jest as well?

@dinoboff
Copy link
Collaborator

dinoboff commented Oct 4, 2017

I am not familiar with Jest test suite; I am not sure what kind of api would work with it. Not all test suite require their own plugin, the default API might be fine; e.g. tap or ava can use the default API directly (something like the chai plugin would be an anti-pattern), although #124 needs a fix.

What would a Jest test for firebase security rules look like?

@dinoboff
Copy link
Collaborator

dinoboff commented Oct 4, 2017

Also, are tests run concurrently?

@fernandopasik
Copy link
Author

fernandopasik commented Oct 4, 2017

Yes, tests run concurrently.

I've tried to extend jest matchers with this code:

import targaryen from 'targaryen/plugins/jasmine';

expect.extend(targaryen.matchers);

but now I'm receiving this error:

Unexpected return from a matcher function.
    Matcher functions should return an object in the following format:
      {message?: string | function, pass: boolean}
    '{"compare": [Function compare]}' was returned

@fernandopasik
Copy link
Author

Looks like your structure is returning a compare function that later returns what's needed by jest

canRead() {

    return {compare(auth, path, now) {

      const data = targaryen.util.getFirebaseData().as(auth);

      const result = data.read(path, now);

      return {
        pass: result.allowed === true,
        message: targaryen.util.unreadableError(result)
      };

    }};

  },

@dinoboff
Copy link
Collaborator

dinoboff commented Oct 4, 2017

I meant try without a matcher, using targaryen API directly, to see what's missing, what a matcher could improve:

const targaryen = require('targaryen');

const rules = {
  rules: {
    foo: {
      '.write': 'true'
    }
  }
};
const initialData = {foo: {bar: 1, baz: 2}};
const database = targaryen.database(rules, initialData).with({debug: true});

test('Anyone can update foo', t => {
  // Note that a database, its internal rules and its data layer are immutable;
  // concurrent tests can use the same database
  const {info, allowed, newDatabase} = database.update('/foo', {bar: 2});
  
  // a Jest matcher could conditionally print the debug info.
  console.log(info);
  expect(allowed).toBe(true);

  // Unlike chai matcher, a new matcher could also allow to test the new data
  expect(newDatabase.snapshot('/foo').val()). toEqual({bar: 2, baz: 2});
});

ps: jest matcher api.

@dinoboff
Copy link
Collaborator

dinoboff commented Oct 7, 2017

@fernandopasik I suggest you create a matcher on one of your project. I would suggest also to use targaryen.util.*Error helpers but to avoid the helpers using global values, targaryen.util.set* or targaryen.util.set*; targaryen has only synchronous methods so they can be used safely with concurrent test, but you need to reset rules and data between each test.

A set of matcher like:

const rules = {
  rules: {
    foo: {
      '.write': 'auth != null'
    }
  }
};
const initialData = {foo: {bar: 1, baz: 2}};
const database = targaryen.database(rules, initialData).with({debug: true});
const alice = {uid: 'alice'};

test('Authenticated user can read foo', t => {
  expect(database).not.toAllowRead('/foo');
  expect(database.as(alice)).toAllowRead('/foo');
  
  // or if jest api allows that
  expect(database).can.not.read('/foo');
  expect(database.as(alice)).can.read('/foo');
});

Once you like the matchers, create a package. I am happy to link it in the doc, but I am not sure it's something I can maintain in core, especially since I am not using jest myself.

@dedan
Copy link

dedan commented Oct 23, 2017

@fernandopasik You can simply use the Chai matchers within your Jest test suites. I found a blog post that describes this setup in detail.

And here is an example of a simple test of mine, using targaryen matchers with Chai within Jest.

const targaryen = require('targaryen/plugins/chai')
const chai = require('chai')
global.chaiExpect = chai.expect

const rules = require('../database.rules.json')

chai.use(targaryen)

beforeEach(() => {
  targaryen.setFirebaseData({})
  targaryen.setFirebaseRules(rules)
})

it('should allow everybody to write to betaEmails', () => {
  chaiExpect(null).cannot.read.path('/betaEmails')
})

@fernandopasik
Copy link
Author

fernandopasik commented Oct 23, 2017

Thanks @dedan. I'd like to continue looking into adapting the jasmine matchers to jest. Usually with jest there is no need to include chai for assertions.

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

No branches or pull requests

3 participants