Mailspring/app/spec/stores/feature-usage-store-spec.ts
Ben Gotow 149b389508
Replace Babel with TypeScript compiler, switch entire app to TypeScript 🎉 (#1404)
* Switch to using Typescript instead of Babel

* Switch all es6 / jsx file extensions to ts / tsx

* Convert Utils to a TS module from module.exports style module

* Move everything from module.exports to typescript exports

* Define .d.ts files for mailspring-exports and component kit… Yes it seems this is the best option :(

* Load up on those @types

* Synthesize TS types from PropTypes for standard components

* Add types to Model classes and move constructor constants to instance vars

* 9800 => 7700 TS errors

* 7700 => 5600 TS errors

* 5600 => 5330 TS errors

* 5330 => 4866 TS errors

* 4866 => 4426 TS errors

* 4426 => 2411 TS errors

* 2411 > 1598 TS errors

* 1598 > 769 TS errors

* 769 > 129 TS errors

* 129 > 22 TS errors

* Fix runtime errors

* More runtime error fixes

* Remove support for custom .es6 file extension

* Remove a few odd remaining references to Nylas

* Don’t ship Typescript support in the compiled app for now

* Fix issues in compiled app - module resolution in TS is case sensitive?

* README updates

* Fix a few more TS errors

* Make “No Signature” option clickable + selectable

* Remove flicker when saving file and reloading keymaps

* Fix mail rule item height in preferences

* Fix missing spacing in thread sharing popover

* Fix scrollbar ticks being nested incorrectly

* Add Japanese as a manually reviewed language

* Prevent the thread list from “sticking”

* Re-use Sheet when switching root tabs, prevent sidebar from resetting

* Ensure specs run

* Update package configuration to avoid shpping types

* Turn eslint back on - we will opt-in to the TS rules one by one
2019-03-04 11:03:12 -08:00

132 lines
4.3 KiB
TypeScript

import { Actions, TaskQueue } from 'mailspring-exports';
import FeatureUsageStore from '../../src/flux/stores/feature-usage-store';
import { IdentityStore } from '../../src/flux/stores/identity-store';
describe('FeatureUsageStore', function featureUsageStoreSpec() {
beforeEach(() => {
this.fakeIdentity = {
id: 'foo',
featureUsage: {
'is-usable': {
quota: 10,
period: 'monthly',
usedInPeriod: 8,
featureLimitName: 'Usable Group A',
},
'not-usable': {
quota: 10,
period: 'monthly',
usedInPeriod: 10,
featureLimitName: 'Unusable Group A',
},
},
};
spyOn(IdentityStore, 'identity').andReturn(this.fakeIdentity);
spyOn(IdentityStore, 'saveIdentity').andCallFake(async ident => {
this.fakeIdentity = ident;
});
});
describe('isUsable', () => {
it("returns true if a feature hasn't met it's quota", () => {
expect(FeatureUsageStore.isUsable('is-usable')).toBe(true);
});
it('returns false if a feature is at its quota', () => {
expect(FeatureUsageStore.isUsable('not-usable')).toBe(false);
});
it('returns true if no quota is present for the feature', () => {
spyOn(AppEnv, 'reportError');
expect(FeatureUsageStore.isUsable('unsupported')).toBe(true);
expect(AppEnv.reportError).toHaveBeenCalled();
});
});
describe('markUsed', () => {
beforeEach(() => {
spyOn(Actions, 'queueTask');
});
afterEach(() => {
TaskQueue._queue = [];
});
it('immediately increments the identity counter', () => {
const before = this.fakeIdentity.featureUsage['is-usable'].usedInPeriod;
FeatureUsageStore.markUsed('is-usable');
const after = this.fakeIdentity.featureUsage['is-usable'].usedInPeriod;
expect(after).toEqual(before + 1);
});
it('queues a task to sync the optimistic changes to the server', () => {
FeatureUsageStore.markUsed('is-usable');
expect(Actions.queueTask).toHaveBeenCalled();
});
});
describe('markUsedOrUpgrade', () => {
beforeEach(() => {
spyOn(FeatureUsageStore, 'markUsed').andReturn(Promise.resolve());
spyOn(Actions, 'openModal');
});
it("marks the feature used if it's usable", async () => {
await FeatureUsageStore.markUsedOrUpgrade('is-usable');
expect(FeatureUsageStore.markUsed).toHaveBeenCalled();
expect(FeatureUsageStore.markUsed.callCount).toBe(1);
});
describe('showing modal', () => {
beforeEach(() => {
this.lexicon = {
headerText: 'all test used',
rechargeText: 'add a test to',
iconUrl: 'icon url',
};
});
it('resolves the modal if you upgrade', async () => {
setImmediate(() => {
this.fakeIdentity.featureUsage['not-usable'].quota = 10000;
FeatureUsageStore._onModalClose();
});
await FeatureUsageStore.markUsedOrUpgrade('not-usable', this.lexicon);
expect(Actions.openModal).toHaveBeenCalled();
expect(Actions.openModal.calls.length).toBe(1);
});
it('pops open a modal with the correct text', async () => {
setImmediate(() => {
this.fakeIdentity.featureUsage['not-usable'].quota = 10000;
FeatureUsageStore._onModalClose();
});
await FeatureUsageStore.markUsedOrUpgrade('not-usable', this.lexicon);
expect(Actions.openModal).toHaveBeenCalled();
expect(Actions.openModal.calls.length).toBe(1);
const component = Actions.openModal.calls[0].args[0].component;
expect(component.props).toEqual({
modalClass: 'not-usable',
headerText: 'all test used',
iconUrl: 'icon url',
rechargeText:
'You can add a test to 10 emails a month with Mailspring Basic. Upgrade to Pro today!',
});
});
it("rejects if you don't upgrade", async () => {
let caughtError = false;
setImmediate(() => {
FeatureUsageStore._onModalClose();
});
try {
await FeatureUsageStore.markUsedOrUpgrade('not-usable', this.lexicon);
} catch (err) {
expect(err instanceof FeatureUsageStore.NoProAccessError).toBe(true);
caughtError = true;
}
expect(caughtError).toBe(true);
});
});
});
});