open-consul/ui-v2/tests/integration/components/data-source-test.js
John Cowen 0a47a95588 ui: Add DataSource component (#7448)
* ui: Add data-source component and related services (#6486)

* ui: Add data-source component and related services:

1. DataSource component
2. Repository manager for retrieving repositories based on URIs
3. Blocking data service for injection to the data-source component to
support blocking query types of data sources
4. 'Once' promise based data service for injection for potential
fallback to old style promise based data (would need to be injected via
an initial runtime variable)
5. Several utility functions taken from elsewhere
  - maybeCall - a replication of code from elsewhere for condition
  calling a function based on the result of a promise
  - restartWhenAvailable - used for restarting blocking queries when a
  tab is brought to the front
  - ifNotBlocking - to check if blocking is NOT enabled

* Move to a different organization based on protocols

* Don't call open twice when eager

* Workaround new ember error for reading and writing at the same time

* Add first draft of a README.mdx file
2020-05-12 17:14:18 +00:00

122 lines
4.3 KiB
JavaScript

import { module } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { clearRender, render, waitUntil } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import test from 'ember-sinon-qunit/test-support/test';
import Service from '@ember/service';
import { BlockingEventSource as RealEventSource } from 'consul-ui/utils/dom/event-source';
const createFakeBlockingEventSource = function() {
const EventSource = function(cb) {
this.readyState = 1;
this.source = cb;
};
const o = EventSource.prototype;
[
'addEventListener',
'removeEventListener',
'dispatchEvent',
'close',
'open',
'getCurrentEvent',
].forEach(function(item) {
o[item] = function() {};
});
return EventSource;
};
const BlockingEventSource = createFakeBlockingEventSource();
module('Integration | Component | data-source', function(hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function() {
this.actions = {};
this.send = (actionName, ...args) => this.actions[actionName].apply(this, args);
});
test('open and closed are called correctly when the src is changed', async function(assert) {
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.set('myAction', function(val) { ... });
assert.expect(9);
const close = this.stub();
const open = this.stub();
const addEventListener = this.stub();
const removeEventListener = this.stub();
let count = 0;
const fakeService = Service.extend({
open: function(uri, obj) {
open(uri);
const source = new BlockingEventSource();
source.getCurrentEvent = function() {
return { data: uri };
};
source.addEventListener = addEventListener;
source.removeEventListener = removeEventListener;
return source;
},
close: close,
});
this.owner.register('service:data-source/fake-service', fakeService);
this.owner.inject('component:data-source', 'data', 'service:data-source/fake-service');
this.actions.change = data => {
count++;
switch (count) {
case 1:
assert.equal(data, 'a', 'change was called first with "a"');
setTimeout(() => this.set('src', 'b'), 0);
break;
case 2:
assert.equal(data, 'b', 'change was called second with "b"');
break;
}
};
this.set('src', 'a');
await render(hbs`<DataSource @src={{src}} @onchange={{action "change" value="data"}} />`);
assert.equal(this.element.textContent.trim(), '');
await waitUntil(() => {
return close.calledTwice;
});
assert.ok(open.calledTwice, 'open is called when src is set');
assert.ok(close.calledTwice, 'close is called as open is called');
await clearRender();
await waitUntil(() => {
return close.calledThrice;
});
assert.ok(open.calledTwice, 'open is _still_ only called when src is set');
assert.ok(close.calledThrice, 'close is called an extra time as the component is destroyed');
assert.equal(addEventListener.callCount, 4, 'all event listeners were added');
assert.equal(removeEventListener.callCount, 4, 'all event listeners were removed');
});
test('error actions are triggered when errors are dispatched', async function(assert) {
const source = new RealEventSource();
const error = this.stub();
const close = this.stub();
const fakeService = Service.extend({
open: function(uri, obj) {
source.getCurrentEvent = function() {
return {};
};
return source;
},
close: close,
});
this.owner.register('service:data-source/fake-service', fakeService);
this.owner.inject('component:data-source', 'data', 'service:data-source/fake-service');
this.actions.change = data => {
source.dispatchEvent({ type: 'error', error: {} });
};
this.actions.error = error;
await render(
hbs`<DataSource @src="" @onchange={{action "change" value="data"}} @onerror={{action "error" value="error"}} />`
);
await waitUntil(() => {
return error.calledOnce;
});
assert.ok(error.calledOnce, 'error action was called');
assert.ok(close.calledOnce, 'close was called before the open');
await clearRender();
assert.ok(close.calledTwice, 'close was also called when the component is destroyed');
});
});