@apollo-elements/fast
Advanced tools
Comparing version 3.0.2 to 3.0.3
import { __decorate } from "tslib"; | ||
import { ApolloMutationController as AMC, } from '@apollo-elements/core/apollo-mutation-controller'; | ||
import { ApolloMutationController as AMC } from '@apollo-elements/core/apollo-mutation-controller'; | ||
import { Observable, observable } from '@microsoft/fast-element'; | ||
@@ -10,48 +10,52 @@ import { FASTControllerHost } from './fast-controller-host'; | ||
*/ | ||
export class ApolloMutationBehavior extends AMC { | ||
constructor(hostElement, mutation, options) { | ||
super(new FASTControllerHost(hostElement), mutation, { ...options, hostElement }); | ||
this.hostElement = hostElement; | ||
/** | ||
* Latest query data. | ||
*/ | ||
this.data = null; | ||
this.called = false; | ||
this.loading = false; | ||
this.error = null; | ||
this.errors = []; | ||
this.variables = options?.variables ?? null; | ||
hostElement.$fastController.addBehaviors([this]); | ||
} | ||
get variables() { | ||
Observable.track(this, 'variables'); | ||
return super.variables; | ||
} | ||
set variables(value) { | ||
super.variables = value; | ||
Observable.notify(this, 'variables'); | ||
} | ||
bind(_source, _context) { | ||
this.hostConnected(); | ||
} | ||
unbind(_source) { | ||
this.hostDisconnected(); | ||
this.host.removeController(this); | ||
} | ||
constructor(hostElement, mutation, options) { | ||
super(new FASTControllerHost(hostElement), mutation, { ...options, | ||
hostElement | ||
}); | ||
this.hostElement = hostElement; | ||
/** | ||
* Latest query data. | ||
*/ | ||
this.data = null; | ||
this.called = false; | ||
this.loading = false; | ||
this.error = null; | ||
this.errors = []; | ||
this.variables = options?.variables ?? null; | ||
hostElement.$fastController.addBehaviors([this]); | ||
} | ||
get variables() { | ||
Observable.track(this, 'variables'); | ||
return super.variables; | ||
} | ||
set variables(value) { | ||
super.variables = value; | ||
Observable.notify(this, 'variables'); | ||
} | ||
bind(_source, _context) { | ||
this.hostConnected(); | ||
} | ||
unbind(_source) { | ||
this.hostDisconnected(); | ||
this.host.removeController(this); | ||
} | ||
} | ||
__decorate([ | ||
observable | ||
], ApolloMutationBehavior.prototype, "data", void 0); | ||
__decorate([ | ||
observable | ||
], ApolloMutationBehavior.prototype, "called", void 0); | ||
__decorate([ | ||
observable | ||
], ApolloMutationBehavior.prototype, "loading", void 0); | ||
__decorate([ | ||
observable | ||
], ApolloMutationBehavior.prototype, "error", void 0); | ||
__decorate([ | ||
observable | ||
], ApolloMutationBehavior.prototype, "errors", void 0); | ||
__decorate([observable], ApolloMutationBehavior.prototype, "data", void 0); | ||
__decorate([observable], ApolloMutationBehavior.prototype, "called", void 0); | ||
__decorate([observable], ApolloMutationBehavior.prototype, "loading", void 0); | ||
__decorate([observable], ApolloMutationBehavior.prototype, "error", void 0); | ||
__decorate([observable], ApolloMutationBehavior.prototype, "errors", void 0); | ||
//# sourceMappingURL=apollo-mutation-behavior.js.map |
import { __decorate } from "tslib"; | ||
import { ApolloQueryController, } from '@apollo-elements/core/apollo-query-controller'; | ||
import { ApolloQueryController } from '@apollo-elements/core/apollo-query-controller'; | ||
import { Observable, observable } from '@microsoft/fast-element'; | ||
@@ -10,42 +10,47 @@ import { FASTControllerHost } from './fast-controller-host.js'; | ||
*/ | ||
export class ApolloQueryBehavior extends ApolloQueryController { | ||
constructor(hostElement, query, options) { | ||
super(new FASTControllerHost(hostElement), query, { ...options, hostElement }); | ||
/** | ||
* Latest query data. | ||
*/ | ||
this.data = null; | ||
this.loading = false; | ||
this.error = null; | ||
this.errors = []; | ||
this.variables = options?.variables ?? null; | ||
hostElement.$fastController.addBehaviors([this]); | ||
} | ||
get variables() { | ||
Observable.track(this, 'variables'); | ||
return super.variables; | ||
} | ||
set variables(value) { | ||
super.variables = value; | ||
Observable.notify(this, 'variables'); | ||
} | ||
bind(_source, _context) { | ||
this.hostConnected(); | ||
} | ||
unbind(_source) { | ||
this.hostDisconnected(); | ||
} | ||
constructor(hostElement, query, options) { | ||
super(new FASTControllerHost(hostElement), query, { ...options, | ||
hostElement | ||
}); | ||
/** | ||
* Latest query data. | ||
*/ | ||
this.data = null; | ||
this.loading = false; | ||
this.error = null; | ||
this.errors = []; | ||
this.variables = options?.variables ?? null; | ||
hostElement.$fastController.addBehaviors([this]); | ||
} | ||
get variables() { | ||
Observable.track(this, 'variables'); | ||
return super.variables; | ||
} | ||
set variables(value) { | ||
super.variables = value; | ||
Observable.notify(this, 'variables'); | ||
} | ||
bind(_source, _context) { | ||
this.hostConnected(); | ||
} | ||
unbind(_source) { | ||
this.hostDisconnected(); | ||
} | ||
} | ||
__decorate([ | ||
observable | ||
], ApolloQueryBehavior.prototype, "data", void 0); | ||
__decorate([ | ||
observable | ||
], ApolloQueryBehavior.prototype, "loading", void 0); | ||
__decorate([ | ||
observable | ||
], ApolloQueryBehavior.prototype, "error", void 0); | ||
__decorate([ | ||
observable | ||
], ApolloQueryBehavior.prototype, "errors", void 0); | ||
__decorate([observable], ApolloQueryBehavior.prototype, "data", void 0); | ||
__decorate([observable], ApolloQueryBehavior.prototype, "loading", void 0); | ||
__decorate([observable], ApolloQueryBehavior.prototype, "error", void 0); | ||
__decorate([observable], ApolloQueryBehavior.prototype, "errors", void 0); | ||
//# sourceMappingURL=apollo-query-behavior.js.map |
import { __decorate } from "tslib"; | ||
import { ApolloSubscriptionController, } from '@apollo-elements/core/apollo-subscription-controller'; | ||
import { ApolloSubscriptionController } from '@apollo-elements/core/apollo-subscription-controller'; | ||
import { Observable, observable } from '@microsoft/fast-element'; | ||
@@ -10,42 +10,47 @@ import { FASTControllerHost } from './fast-controller-host'; | ||
*/ | ||
export class ApolloSubscriptionBehavior extends ApolloSubscriptionController { | ||
constructor(hostElement, subscription, options) { | ||
super(new FASTControllerHost(hostElement), subscription, { ...options, hostElement }); | ||
/** | ||
* Latest query data. | ||
*/ | ||
this.data = null; | ||
this.loading = false; | ||
this.error = null; | ||
this.errors = []; | ||
this.variables = options?.variables ?? null; | ||
hostElement.$fastController.addBehaviors([this]); | ||
} | ||
get variables() { | ||
Observable.track(this, 'variables'); | ||
return super.variables; | ||
} | ||
set variables(value) { | ||
super.variables = value; | ||
Observable.notify(this, 'variables'); | ||
} | ||
bind(_source, _context) { | ||
this.hostConnected(); | ||
} | ||
unbind(_source) { | ||
this.hostDisconnected(); | ||
} | ||
constructor(hostElement, subscription, options) { | ||
super(new FASTControllerHost(hostElement), subscription, { ...options, | ||
hostElement | ||
}); | ||
/** | ||
* Latest query data. | ||
*/ | ||
this.data = null; | ||
this.loading = false; | ||
this.error = null; | ||
this.errors = []; | ||
this.variables = options?.variables ?? null; | ||
hostElement.$fastController.addBehaviors([this]); | ||
} | ||
get variables() { | ||
Observable.track(this, 'variables'); | ||
return super.variables; | ||
} | ||
set variables(value) { | ||
super.variables = value; | ||
Observable.notify(this, 'variables'); | ||
} | ||
bind(_source, _context) { | ||
this.hostConnected(); | ||
} | ||
unbind(_source) { | ||
this.hostDisconnected(); | ||
} | ||
} | ||
__decorate([ | ||
observable | ||
], ApolloSubscriptionBehavior.prototype, "data", void 0); | ||
__decorate([ | ||
observable | ||
], ApolloSubscriptionBehavior.prototype, "loading", void 0); | ||
__decorate([ | ||
observable | ||
], ApolloSubscriptionBehavior.prototype, "error", void 0); | ||
__decorate([ | ||
observable | ||
], ApolloSubscriptionBehavior.prototype, "errors", void 0); | ||
__decorate([observable], ApolloSubscriptionBehavior.prototype, "data", void 0); | ||
__decorate([observable], ApolloSubscriptionBehavior.prototype, "loading", void 0); | ||
__decorate([observable], ApolloSubscriptionBehavior.prototype, "error", void 0); | ||
__decorate([observable], ApolloSubscriptionBehavior.prototype, "errors", void 0); | ||
//# sourceMappingURL=apollo-subscription-behavior.js.map |
@@ -15,69 +15,75 @@ import { __decorate } from "tslib"; | ||
*/ | ||
export class ApolloElement extends FASTElement { | ||
constructor() { | ||
super(...arguments); | ||
this.readyToReceiveDocument = false; | ||
/** @summary The Apollo Client instance */ | ||
this.client = window.__APOLLO_CLIENT__ ?? null; | ||
/** | ||
* @summary Operation document. | ||
* GraphQL operation document i.e. query, subscription, or mutation. | ||
* Must be a parsed GraphQL `DocumentNode` | ||
*/ | ||
this.document = null; | ||
/** @summary Whether a request is in flight. */ | ||
this.loading = false; | ||
/** @summary Latest Data. */ | ||
this.data = null; | ||
/** @summary Operation variables. */ | ||
this.variables = null; | ||
/** @summary Latest error */ | ||
this.error = null; | ||
/** @summary Latest errors */ | ||
this.errors = []; | ||
} | ||
connectedCallback() { | ||
this.readyToReceiveDocument = true; | ||
super.connectedCallback(); | ||
this.dispatchEvent(new ApolloElementEvent('apollo-element-connected', this)); | ||
} | ||
disconnectedCallback() { | ||
this.readyToReceiveDocument = false; | ||
this.dispatchEvent(new ApolloElementEvent('apollo-element-disconnected', this)); | ||
window.dispatchEvent(new ApolloElementEvent('apollo-element-disconnected', this)); | ||
super.disconnectedCallback?.(); /* c8 ignore start */ // manual testing showed that both cases were hit | ||
} | ||
constructor() { | ||
super(...arguments); | ||
this.readyToReceiveDocument = false; | ||
/** @summary The Apollo Client instance */ | ||
this.client = window.__APOLLO_CLIENT__ ?? null; | ||
/** | ||
* @summary Operation document. | ||
* GraphQL operation document i.e. query, subscription, or mutation. | ||
* Must be a parsed GraphQL `DocumentNode` | ||
*/ | ||
this.document = null; | ||
/** @summary Whether a request is in flight. */ | ||
this.loading = false; | ||
/** @summary Latest Data. */ | ||
this.data = null; | ||
/** @summary Operation variables. */ | ||
this.variables = null; | ||
/** @summary Latest error */ | ||
this.error = null; | ||
/** @summary Latest errors */ | ||
this.errors = []; | ||
} | ||
connectedCallback() { | ||
this.readyToReceiveDocument = true; | ||
super.connectedCallback(); | ||
this.dispatchEvent(new ApolloElementEvent('apollo-element-connected', this)); | ||
} | ||
disconnectedCallback() { | ||
this.readyToReceiveDocument = false; | ||
this.dispatchEvent(new ApolloElementEvent('apollo-element-disconnected', this)); | ||
window.dispatchEvent(new ApolloElementEvent('apollo-element-disconnected', this)); | ||
super.disconnectedCallback?.(); | ||
/* c8 ignore start */ | ||
// manual testing showed that both cases were hit | ||
} | ||
} | ||
__decorate([ | ||
observable, | ||
hosted(), | ||
controlled() | ||
], ApolloElement.prototype, "client", void 0); | ||
__decorate([ | ||
hosted(), | ||
controlled() | ||
], ApolloElement.prototype, "document", void 0); | ||
__decorate([ | ||
hosted({ path: 'options' }), | ||
controlled({ path: 'options' }) | ||
], ApolloElement.prototype, "context", void 0); | ||
__decorate([ | ||
controlled({ onSet(v) { this.toggleAttribute('loading', v); } }) | ||
], ApolloElement.prototype, "loading", void 0); | ||
__decorate([ | ||
hosted(), | ||
controlled() | ||
], ApolloElement.prototype, "data", void 0); | ||
__decorate([ | ||
hosted(), | ||
controlled() | ||
], ApolloElement.prototype, "variables", void 0); | ||
__decorate([ | ||
hosted(), | ||
controlled() | ||
], ApolloElement.prototype, "error", void 0); | ||
__decorate([ | ||
hosted(), | ||
controlled() | ||
], ApolloElement.prototype, "errors", void 0); | ||
__decorate([observable, hosted(), controlled()], ApolloElement.prototype, "client", void 0); | ||
__decorate([hosted(), controlled()], ApolloElement.prototype, "document", void 0); | ||
__decorate([hosted({ | ||
path: 'options' | ||
}), controlled({ | ||
path: 'options' | ||
})], ApolloElement.prototype, "context", void 0); | ||
__decorate([controlled({ | ||
onSet(v) { | ||
this.toggleAttribute('loading', v); | ||
} | ||
})], ApolloElement.prototype, "loading", void 0); | ||
__decorate([hosted(), controlled()], ApolloElement.prototype, "data", void 0); | ||
__decorate([hosted(), controlled()], ApolloElement.prototype, "variables", void 0); | ||
__decorate([hosted(), controlled()], ApolloElement.prototype, "error", void 0); | ||
__decorate([hosted(), controlled()], ApolloElement.prototype, "errors", void 0); | ||
//# sourceMappingURL=apollo-element.js.map |
@@ -8,76 +8,80 @@ import { __decorate } from "tslib"; | ||
describe('[fast] ApolloElement', function describeApolloElement() { | ||
it('is an instance of FASTElement', async function () { | ||
const name = 'is-an-instance-of-f-a-s-t-element'; | ||
let Test = class Test extends ApolloElement { | ||
dataChanged(oldVal, newVal) { | ||
oldVal; | ||
newVal; | ||
} | ||
}; | ||
Test = __decorate([ | ||
customElement({ name }) | ||
], Test); | ||
const tag = unsafeStatic(name); | ||
const element = await fixture(h `<${tag}></${tag}>`); | ||
expect(element).to.be.an.instanceOf(FASTElement); | ||
}); | ||
it('renders when client is set', async function rendersOnClient() { | ||
const name = 'renders-when-client-is-set'; | ||
// @ts-expect-error: just testing assignment and rendering | ||
const template = html `${x => x.client?.test ?? 'FAIL'}`; | ||
let Test = class Test extends ApolloElement { | ||
}; | ||
Test = __decorate([ | ||
customElement({ name, template }) | ||
], Test); | ||
const tag = unsafeStatic(name); | ||
const element = await fixture(h `<${tag}></${tag}>`); | ||
// @ts-expect-error: just testing assignment and rendering | ||
element.client = { test: 'CLIENT' }; | ||
await DOM.nextUpdate(); | ||
expect(element.shadowRoot.textContent).to.equal('CLIENT'); | ||
}); | ||
it('renders when error is set', async function rendersOnError() { | ||
const name = 'renders-when-error-is-set'; | ||
const template = html `${x => x.error ?? 'FAIL'}`; | ||
let Test = class Test extends ApolloElement { | ||
}; | ||
Test = __decorate([ | ||
customElement({ name, template }) | ||
], Test); | ||
const tag = unsafeStatic(name); | ||
const element = await fixture(h `<${tag} .error="${'error'}"></${tag}>`); | ||
expect(element).shadowDom.to.equal('error'); | ||
}); | ||
it('renders when loading is set', async function rendersOnLoading() { | ||
const name = 'renders-when-loading-is-set'; | ||
const template = html `${x => x.loading ?? false ? 'LOADING' : 'FAIL'}`; | ||
let Test = class Test extends ApolloElement { | ||
}; | ||
Test = __decorate([ | ||
customElement({ name, template }) | ||
], Test); | ||
const tag = unsafeStatic(name); | ||
const element = await fixture(h `<${tag} .loading="${true}"></${tag}>`); | ||
expect(element).shadowDom.to.equal('LOADING'); | ||
}); | ||
it('is an instance of FASTElement', async function () { | ||
const name = 'is-an-instance-of-f-a-s-t-element'; | ||
let Test = class Test extends ApolloElement { | ||
dataChanged(oldVal, newVal) { | ||
oldVal; | ||
newVal; | ||
} | ||
}; | ||
Test = __decorate([customElement({ | ||
name | ||
})], Test); | ||
const tag = unsafeStatic(name); | ||
const element = await fixture(h`<${tag}></${tag}>`); | ||
expect(element).to.be.an.instanceOf(FASTElement); | ||
}); | ||
it('renders when client is set', async function rendersOnClient() { | ||
const name = 'renders-when-client-is-set'; // @ts-expect-error: just testing assignment and rendering | ||
const template = html`${x => x.client?.test ?? 'FAIL'}`; | ||
let Test = class Test extends ApolloElement {}; | ||
Test = __decorate([customElement({ | ||
name, | ||
template | ||
})], Test); | ||
const tag = unsafeStatic(name); | ||
const element = await fixture(h`<${tag}></${tag}>`); // @ts-expect-error: just testing assignment and rendering | ||
element.client = { | ||
test: 'CLIENT' | ||
}; | ||
await DOM.nextUpdate(); | ||
expect(element.shadowRoot.textContent).to.equal('CLIENT'); | ||
}); | ||
it('renders when error is set', async function rendersOnError() { | ||
const name = 'renders-when-error-is-set'; | ||
const template = html`${x => x.error ?? 'FAIL'}`; | ||
let Test = class Test extends ApolloElement {}; | ||
Test = __decorate([customElement({ | ||
name, | ||
template | ||
})], Test); | ||
const tag = unsafeStatic(name); | ||
const element = await fixture(h`<${tag} .error="${'error'}"></${tag}>`); | ||
expect(element).shadowDom.to.equal('error'); | ||
}); | ||
it('renders when loading is set', async function rendersOnLoading() { | ||
const name = 'renders-when-loading-is-set'; | ||
const template = html`${x => x.loading ?? false ? 'LOADING' : 'FAIL'}`; | ||
let Test = class Test extends ApolloElement {}; | ||
Test = __decorate([customElement({ | ||
name, | ||
template | ||
})], Test); | ||
const tag = unsafeStatic(name); | ||
const element = await fixture(h`<${tag} .loading="${true}"></${tag}>`); | ||
expect(element).shadowDom.to.equal('LOADING'); | ||
}); | ||
}); | ||
class TypeCheck extends ApolloElement { | ||
typeCheck() { | ||
/* eslint-disable func-call-spacing, no-multi-spaces */ | ||
assertType(this); | ||
assertType(this); | ||
// ApolloElementInterface | ||
assertType(this.client); | ||
assertType(this.context); | ||
assertType(this.loading); | ||
assertType(this.document); | ||
assertType(this.error); | ||
assertType(this.errors); | ||
assertType(this.error.message); | ||
if (isApolloError(this.error)) | ||
assertType(this.error.graphQLErrors); | ||
/* eslint-enable func-call-spacing, no-multi-spaces */ | ||
} | ||
typeCheck() { | ||
/* eslint-disable func-call-spacing, no-multi-spaces */ | ||
assertType(this); | ||
assertType(this); // ApolloElementInterface | ||
assertType(this.client); | ||
assertType(this.context); | ||
assertType(this.loading); | ||
assertType(this.document); | ||
assertType(this.error); | ||
assertType(this.errors); | ||
assertType(this.error.message); | ||
if (isApolloError(this.error)) assertType(this.error.graphQLErrors); | ||
/* eslint-enable func-call-spacing, no-multi-spaces */ | ||
} | ||
} | ||
//# sourceMappingURL=apollo-element.test.js.map |
@@ -17,82 +17,113 @@ import { __decorate } from "tslib"; | ||
*/ | ||
export class ApolloMutation extends ApolloElement { | ||
constructor() { | ||
super(...arguments); | ||
this.controller = new ApolloMutationBehavior(this, null, { | ||
onCompleted: data => this.onCompleted?.(data), | ||
onError: error => this.onError?.(error), /* c8 ignore next */ // covered | ||
}); | ||
/** | ||
* @summary Whether the mutation was called | ||
*/ | ||
this.called = false; | ||
/** @summary The mutation. */ | ||
this.mutation = null; | ||
/** | ||
* @summary If true, the returned data property will not update with the mutation result. | ||
*/ | ||
this.ignoreResults = false; | ||
/** | ||
* As an attribute, can be a string of comma-separated query names | ||
* ```html | ||
* <mutation-element refetch-queries="QueryA, QueryB,QueryC"></mutation-element> | ||
* ``` | ||
* As a property, you can pass any legal `refetchQueries` value. | ||
*/ | ||
this.refetchQueries = null; | ||
constructor() { | ||
super(...arguments); | ||
this.controller = new ApolloMutationBehavior(this, null, { | ||
onCompleted: data => this.onCompleted?.(data), | ||
onError: error => this.onError?.(error) | ||
/* c8 ignore next */ | ||
// covered | ||
}); | ||
/** | ||
* @summary Whether the mutation was called | ||
*/ | ||
this.called = false; | ||
/** @summary The mutation. */ | ||
this.mutation = null; | ||
/** | ||
* @summary If true, the returned data property will not update with the mutation result. | ||
*/ | ||
this.ignoreResults = false; | ||
/** | ||
* As an attribute, can be a string of comma-separated query names | ||
* ```html | ||
* <mutation-element refetch-queries="QueryA, QueryB,QueryC"></mutation-element> | ||
* ``` | ||
* As a property, you can pass any legal `refetchQueries` value. | ||
*/ | ||
this.refetchQueries = null; | ||
} | ||
mutate(params) { | ||
return this.controller.mutate({ ...params, | ||
update: params?.update ?? this.updater | ||
}); | ||
} | ||
} | ||
__decorate([controlled({ | ||
onSet(v) { | ||
this.toggleAttribute('called', v); | ||
} | ||
})], ApolloMutation.prototype, "called", void 0); | ||
__decorate([hosted(), controlled()], ApolloMutation.prototype, "mutation", void 0); | ||
__decorate([hosted({ | ||
path: 'options' | ||
}), controlled({ | ||
path: 'options' | ||
})], ApolloMutation.prototype, "optimisticResponse", void 0); | ||
__decorate([hosted({ | ||
path: 'options' | ||
}), controlled({ | ||
path: 'options' | ||
}), attr({ | ||
mode: 'boolean', | ||
attribute: 'ignore-results' | ||
})], ApolloMutation.prototype, "ignoreResults", void 0); | ||
__decorate([hosted({ | ||
path: 'options' | ||
}), controlled({ | ||
path: 'options' | ||
}), attr({ | ||
mode: 'boolean', | ||
attribute: 'await-refetch-queries' | ||
})], ApolloMutation.prototype, "awaitRefetchQueries", void 0); | ||
__decorate([hosted({ | ||
path: 'options' | ||
}), controlled({ | ||
path: 'options' | ||
}), attr({ | ||
attribute: 'error-policy' | ||
})], ApolloMutation.prototype, "errorPolicy", void 0); | ||
__decorate([hosted({ | ||
path: 'options' | ||
}), controlled({ | ||
path: 'options' | ||
}), attr({ | ||
attribute: 'fetch-policy' | ||
})], ApolloMutation.prototype, "fetchPolicy", void 0); | ||
__decorate([hosted({ | ||
path: 'options' | ||
}), controlled({ | ||
path: 'options' | ||
}), attr({ | ||
mode: 'fromView', | ||
attribute: 'refetch-queries', | ||
converter: { | ||
toView() { | ||
/* c8 ignore next */ | ||
return null; | ||
}, | ||
fromView(value) { | ||
return typeof value !== 'string' ? value : splitCommasAndTrim(value); | ||
} | ||
mutate(params) { | ||
return this.controller.mutate({ | ||
...params, | ||
update: params?.update ?? this.updater, | ||
}); | ||
} | ||
} | ||
__decorate([ | ||
controlled({ onSet(v) { | ||
this.toggleAttribute('called', v); | ||
} }) | ||
], ApolloMutation.prototype, "called", void 0); | ||
__decorate([ | ||
hosted(), | ||
controlled() | ||
], ApolloMutation.prototype, "mutation", void 0); | ||
__decorate([ | ||
hosted({ path: 'options' }), | ||
controlled({ path: 'options' }) | ||
], ApolloMutation.prototype, "optimisticResponse", void 0); | ||
__decorate([ | ||
hosted({ path: 'options' }), | ||
controlled({ path: 'options' }), | ||
attr({ mode: 'boolean', attribute: 'ignore-results' }) | ||
], ApolloMutation.prototype, "ignoreResults", void 0); | ||
__decorate([ | ||
hosted({ path: 'options' }), | ||
controlled({ path: 'options' }), | ||
attr({ mode: 'boolean', attribute: 'await-refetch-queries' }) | ||
], ApolloMutation.prototype, "awaitRefetchQueries", void 0); | ||
__decorate([ | ||
hosted({ path: 'options' }), | ||
controlled({ path: 'options' }), | ||
attr({ attribute: 'error-policy' }) | ||
], ApolloMutation.prototype, "errorPolicy", void 0); | ||
__decorate([ | ||
hosted({ path: 'options' }), | ||
controlled({ path: 'options' }), | ||
attr({ attribute: 'fetch-policy' }) | ||
], ApolloMutation.prototype, "fetchPolicy", void 0); | ||
__decorate([ | ||
hosted({ path: 'options' }), | ||
controlled({ path: 'options' }), | ||
attr({ | ||
mode: 'fromView', | ||
attribute: 'refetch-queries', | ||
converter: { | ||
toView() { /* c8 ignore next */ return null; }, | ||
fromView(value) { | ||
return typeof value !== 'string' ? value : splitCommasAndTrim(value); | ||
}, | ||
}, | ||
}) | ||
], ApolloMutation.prototype, "refetchQueries", void 0); | ||
} | ||
})], ApolloMutation.prototype, "refetchQueries", void 0); | ||
//# sourceMappingURL=apollo-mutation.js.map |
import { __decorate } from "tslib"; | ||
import { setupSpies, setupStubs, } from '@apollo-elements/test'; | ||
import { setupSpies, setupStubs } from '@apollo-elements/test'; | ||
import { expect, fixture } from '@open-wc/testing'; | ||
import { html as h, unsafeStatic } from 'lit/static-html.js'; | ||
import { setupClient, teardownClient, isApolloError, assertType, stringify, } from '@apollo-elements/test'; | ||
import { setupClient, teardownClient, isApolloError, assertType, stringify } from '@apollo-elements/test'; | ||
import { ApolloMutation } from './apollo-mutation'; | ||
import { FASTElement, html, customElement, DOM } from '@microsoft/fast-element'; | ||
import { describeMutation } from '@apollo-elements/test/mutation.test'; | ||
const template = html ` | ||
const template = html` | ||
<output id="called">${x => stringify(x.called)}</output> | ||
@@ -18,197 +18,212 @@ <output id="data">${x => stringify(x.data)}</output> | ||
let TestableApolloMutation = class TestableApolloMutation extends ApolloMutation { | ||
async hasRendered() { | ||
await DOM.nextUpdate(); | ||
return this; | ||
} | ||
$(id) { | ||
return this.shadowRoot.getElementById(id); | ||
} | ||
async hasRendered() { | ||
await DOM.nextUpdate(); | ||
return this; | ||
} | ||
$(id) { | ||
return this.shadowRoot.getElementById(id); | ||
} | ||
}; | ||
TestableApolloMutation = __decorate([ | ||
customElement({ name: 'fast-testable-apollo-mutation-class', template }) | ||
], TestableApolloMutation); | ||
TestableApolloMutation = __decorate([customElement({ | ||
name: 'fast-testable-apollo-mutation-class', | ||
template | ||
})], TestableApolloMutation); | ||
describe('[fast] ApolloMutation', function describeApolloMutation() { | ||
describeMutation({ | ||
async setupFunction(options = {}) { | ||
const name = `fast-setup-function-element-${counter++}`; | ||
const { properties, attributes, innerHTML = '' } = options; | ||
let Test = class Test extends TestableApolloMutation { | ||
}; | ||
Test = __decorate([ | ||
customElement({ name, template }) | ||
], Test); | ||
const attrs = attributes ? ` ${attributes}` : ''; | ||
// for mutation components, which don't fetch on connect, | ||
// and have optional instance callbacks, | ||
// we must ensure spies are created *after* properties are applied | ||
if (properties?.onCompleted) | ||
Test.prototype.onCompleted = properties.onCompleted; | ||
if (properties?.onError) | ||
Test.prototype.onError = properties.onError; | ||
const element = await fixture(`<${name}${attrs}>${innerHTML}</${name}>`); | ||
const spies = setupSpies(options?.spy, Test.prototype); | ||
const stubs = setupStubs(options?.stub, Test.prototype); | ||
for (const [key, val] of Object.entries(properties ?? {})) | ||
key !== 'onCompleted' && key !== 'onError' && (element[key] = val); | ||
await DOM.nextUpdate(); | ||
return { element, spies, stubs }; | ||
}, | ||
describeMutation({ | ||
async setupFunction(options = {}) { | ||
const name = `fast-setup-function-element-${counter++}`; | ||
const { | ||
properties, | ||
attributes, | ||
innerHTML = '' | ||
} = options; | ||
let Test = class Test extends TestableApolloMutation {}; | ||
Test = __decorate([customElement({ | ||
name, | ||
template | ||
})], Test); | ||
const attrs = attributes ? ` ${attributes}` : ''; // for mutation components, which don't fetch on connect, | ||
// and have optional instance callbacks, | ||
// we must ensure spies are created *after* properties are applied | ||
if (properties?.onCompleted) Test.prototype.onCompleted = properties.onCompleted; | ||
if (properties?.onError) Test.prototype.onError = properties.onError; | ||
const element = await fixture(`<${name}${attrs}>${innerHTML}</${name}>`); | ||
const spies = setupSpies(options?.spy, Test.prototype); | ||
const stubs = setupStubs(options?.stub, Test.prototype); | ||
for (const [key, val] of Object.entries(properties ?? {})) key !== 'onCompleted' && key !== 'onError' && (element[key] = val); | ||
await DOM.nextUpdate(); | ||
return { | ||
element, | ||
spies, | ||
stubs | ||
}; | ||
} | ||
}); | ||
describe('subclassing', function () { | ||
beforeEach(setupClient); | ||
afterEach(teardownClient); | ||
it('is an instance of FASTElement', async function () { | ||
const name = 'is-an-instance-of-f-a-s-t-element'; | ||
let Test = class Test extends ApolloMutation {}; | ||
Test = __decorate([customElement({ | ||
name | ||
})], Test); | ||
const el = await fixture(`<${name}></${name}>`); | ||
expect(el).to.be.an.instanceOf(FASTElement); | ||
}); | ||
describe('subclassing', function () { | ||
beforeEach(setupClient); | ||
afterEach(teardownClient); | ||
it('is an instance of FASTElement', async function () { | ||
const name = 'is-an-instance-of-f-a-s-t-element'; | ||
let Test = class Test extends ApolloMutation { | ||
}; | ||
Test = __decorate([ | ||
customElement({ name }) | ||
], Test); | ||
const el = await fixture(`<${name}></${name}>`); | ||
expect(el).to.be.an.instanceOf(FASTElement); | ||
it('renders when data is set', async function rendersOnData() { | ||
const name = 'renders-when-data-is-set'; | ||
const template = html`${x => x.data?.foo ?? 'FAIL'}`; | ||
let Test = class Test extends ApolloMutation {}; | ||
Test = __decorate([customElement({ | ||
name, | ||
template | ||
})], Test); | ||
const tag = unsafeStatic(name); | ||
const element = await fixture(h`<${tag} .data="${{ | ||
foo: 'bar' | ||
}}"></${tag}>`); | ||
expect(element).shadowDom.to.equal('bar'); | ||
}); | ||
describe('refetchQueries', function () { | ||
let element; | ||
class Test extends ApolloMutation {} | ||
describe(`when refetch-queries attribute set with comma-separated, badly-formatted query names`, function () { | ||
beforeEach(async function () { | ||
const name = `refetch-queries-attribute-${Date.now()}`; | ||
let Klass = class Klass extends Test {}; | ||
Klass = __decorate([customElement({ | ||
name | ||
})], Klass); | ||
element = await fixture(`<${name} refetch-queries="A, B,C, D"></${name}>`); | ||
await DOM.nextUpdate(); | ||
}); | ||
it('renders when data is set', async function rendersOnData() { | ||
const name = 'renders-when-data-is-set'; | ||
const template = html `${x => x.data?.foo ?? 'FAIL'}`; | ||
let Test = class Test extends ApolloMutation { | ||
}; | ||
Test = __decorate([ | ||
customElement({ name, template }) | ||
], Test); | ||
const tag = unsafeStatic(name); | ||
const element = await fixture(h `<${tag} .data="${{ foo: 'bar' }}"></${tag}>`); | ||
expect(element).shadowDom.to.equal('bar'); | ||
it('sets the property as an array of query names', function () { | ||
expect(element.refetchQueries).to.deep.equal(['A', 'B', 'C', 'D']); | ||
}); | ||
describe('refetchQueries', function () { | ||
let element; | ||
class Test extends ApolloMutation { | ||
} | ||
describe(`when refetch-queries attribute set with comma-separated, badly-formatted query names`, function () { | ||
beforeEach(async function () { | ||
const name = `refetch-queries-attribute-${Date.now()}`; | ||
let Klass = class Klass extends Test { | ||
}; | ||
Klass = __decorate([ | ||
customElement({ name }) | ||
], Klass); | ||
element = await fixture(`<${name} refetch-queries="A, B,C, D"></${name}>`); | ||
await DOM.nextUpdate(); | ||
}); | ||
it('sets the property as an array of query names', function () { | ||
expect(element.refetchQueries) | ||
.to.deep.equal(['A', 'B', 'C', 'D']); | ||
}); | ||
}); | ||
describe('when refetchQueries property set as array of query names', function () { | ||
const refetchQueries = ['A', 'B', 'C', 'D']; | ||
beforeEach(async function setupElement() { | ||
const name = `refetch-queries-property-${counter++}-${Math.floor(Math.random() * Date.now())}`; | ||
let Klass = class Klass extends Test { | ||
}; | ||
Klass = __decorate([ | ||
customElement({ name }) | ||
], Klass); | ||
element = await fixture(`<${name}></${name}>`); | ||
}); | ||
beforeEach(async function setRefetchQueries() { | ||
element.refetchQueries = refetchQueries; | ||
await DOM.nextUpdate(); | ||
}); | ||
it('sets the property as an array of query names', function () { | ||
expect(element.refetchQueries).to.deep.equal(refetchQueries); | ||
}); | ||
it('does not reflect', function () { | ||
expect(element.getAttribute('refetch-queries')).to.be.null; | ||
}); | ||
}); | ||
describe('when refetchQueries property nullified', function () { | ||
const refetchQueries = null; | ||
beforeEach(async function setupElement() { | ||
const name = `refetch-queries-property-${counter++}-${Math.floor(Math.random() * Date.now())}`; | ||
let Klass = class Klass extends Test { | ||
}; | ||
Klass = __decorate([ | ||
customElement({ name }) | ||
], Klass); | ||
element = await fixture(`<${name}></${name}>`); | ||
}); | ||
beforeEach(async function setRefetchQueries() { | ||
element.refetchQueries = refetchQueries; | ||
await DOM.nextUpdate(); | ||
}); | ||
it('sets the property as an array of query names', function () { | ||
expect(element.refetchQueries).to.be.null; | ||
}); | ||
it('does not reflect', function () { | ||
expect(element.getAttribute('refetch-queries')).to.be.null; | ||
}); | ||
}); | ||
}); | ||
describe('when refetchQueries property set as array of query names', function () { | ||
const refetchQueries = ['A', 'B', 'C', 'D']; | ||
beforeEach(async function setupElement() { | ||
const name = `refetch-queries-property-${counter++}-${Math.floor(Math.random() * Date.now())}`; | ||
let Klass = class Klass extends Test {}; | ||
Klass = __decorate([customElement({ | ||
name | ||
})], Klass); | ||
element = await fixture(`<${name}></${name}>`); | ||
}); | ||
beforeEach(async function setRefetchQueries() { | ||
element.refetchQueries = refetchQueries; | ||
await DOM.nextUpdate(); | ||
}); | ||
it('sets the property as an array of query names', function () { | ||
expect(element.refetchQueries).to.deep.equal(refetchQueries); | ||
}); | ||
it('does not reflect', function () { | ||
expect(element.getAttribute('refetch-queries')).to.be.null; | ||
}); | ||
}); | ||
describe('when refetchQueries property nullified', function () { | ||
const refetchQueries = null; | ||
beforeEach(async function setupElement() { | ||
const name = `refetch-queries-property-${counter++}-${Math.floor(Math.random() * Date.now())}`; | ||
let Klass = class Klass extends Test {}; | ||
Klass = __decorate([customElement({ | ||
name | ||
})], Klass); | ||
element = await fixture(`<${name}></${name}>`); | ||
}); | ||
beforeEach(async function setRefetchQueries() { | ||
element.refetchQueries = refetchQueries; | ||
await DOM.nextUpdate(); | ||
}); | ||
it('sets the property as an array of query names', function () { | ||
expect(element.refetchQueries).to.be.null; | ||
}); | ||
it('does not reflect', function () { | ||
expect(element.getAttribute('refetch-queries')).to.be.null; | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
class TypeCheck extends ApolloMutation { | ||
typeCheck() { | ||
/* eslint-disable max-len, func-call-spacing, no-multi-spaces */ | ||
assertType(this); | ||
assertType(this); | ||
// ApolloElementInterface | ||
assertType(this.client); | ||
assertType(this.context); | ||
assertType(this.loading); | ||
assertType(this.document); | ||
assertType(this.error); | ||
assertType(this.errors); | ||
assertType(this.data); | ||
assertType(this.error.message); | ||
assertType(this.data.a); | ||
// @ts-expect-error: b as number type | ||
assertType(this.data.b); | ||
if (isApolloError(this.error)) | ||
assertType(this.error.graphQLErrors); | ||
// ApolloMutationInterface | ||
assertType(this.mutation); | ||
assertType(this.variables); | ||
assertType(this.called); | ||
assertType(this.ignoreResults); | ||
assertType(this.awaitRefetchQueries); | ||
assertType(this.errorPolicy); | ||
assertType(this.errorPolicy); | ||
// @ts-expect-error: ErrorPolicy is not a number | ||
assertType(this.errorPolicy); | ||
assertType(this.fetchPolicy); | ||
assertType(this.fetchPolicy); | ||
if (typeof this.refetchQueries === 'function') | ||
assertType(this.refetchQueries); | ||
else | ||
assertType(this.refetchQueries); | ||
if (typeof this.optimisticResponse !== 'function') | ||
assertType(this.optimisticResponse); | ||
else | ||
assertType(this.optimisticResponse); | ||
/* eslint-enable max-len, func-call-spacing, no-multi-spaces */ | ||
} | ||
typeCheck() { | ||
/* eslint-disable max-len, func-call-spacing, no-multi-spaces */ | ||
assertType(this); | ||
assertType(this); // ApolloElementInterface | ||
assertType(this.client); | ||
assertType(this.context); | ||
assertType(this.loading); | ||
assertType(this.document); | ||
assertType(this.error); | ||
assertType(this.errors); | ||
assertType(this.data); | ||
assertType(this.error.message); | ||
assertType(this.data.a); // @ts-expect-error: b as number type | ||
assertType(this.data.b); | ||
if (isApolloError(this.error)) assertType(this.error.graphQLErrors); // ApolloMutationInterface | ||
assertType(this.mutation); | ||
assertType(this.variables); | ||
assertType(this.called); | ||
assertType(this.ignoreResults); | ||
assertType(this.awaitRefetchQueries); | ||
assertType(this.errorPolicy); | ||
assertType(this.errorPolicy); // @ts-expect-error: ErrorPolicy is not a number | ||
assertType(this.errorPolicy); | ||
assertType(this.fetchPolicy); | ||
assertType(this.fetchPolicy); | ||
if (typeof this.refetchQueries === 'function') assertType(this.refetchQueries);else assertType(this.refetchQueries); | ||
if (typeof this.optimisticResponse !== 'function') assertType(this.optimisticResponse);else assertType(this.optimisticResponse); | ||
/* eslint-enable max-len, func-call-spacing, no-multi-spaces */ | ||
} | ||
} | ||
class TDNTypeCheck extends ApolloMutation { | ||
typeCheck() { | ||
this.data; | ||
assertType(this.data); | ||
assertType(this.variables); | ||
assertType(this.mutation); | ||
} | ||
typeCheck() { | ||
this.data; | ||
assertType(this.data); | ||
assertType(this.variables); | ||
assertType(this.mutation); | ||
} | ||
} | ||
class TypeCheckAccessor extends ApolloMutation { | ||
// @ts-expect-error: current typescript versions don't allow this type of override | ||
get variables() { | ||
return { param: 'string' }; | ||
} | ||
set variables(v) { | ||
null; | ||
} | ||
// @ts-expect-error: current typescript versions don't allow this type of override | ||
get variables() { | ||
return { | ||
param: 'string' | ||
}; | ||
} | ||
set variables(v) { | ||
null; | ||
} | ||
} | ||
class TypeCheckProperty extends ApolloMutation { | ||
constructor() { | ||
super(...arguments); | ||
this.variables = { param: 'string' }; | ||
} | ||
constructor() { | ||
super(...arguments); | ||
this.variables = { | ||
param: 'string' | ||
}; | ||
} | ||
} | ||
//# sourceMappingURL=apollo-mutation.test.js.map |
@@ -18,172 +18,226 @@ import { __decorate } from "tslib"; | ||
*/ | ||
export class ApolloQuery extends ApolloElement { | ||
constructor() { | ||
super(...arguments); | ||
this.controller = new ApolloQueryBehavior(this, null, { | ||
shouldSubscribe: options => this.readyToReceiveDocument && this.shouldSubscribe(options), | ||
onData: data => this.onData?.(data), | ||
onError: error => this.onError?.(error), /* c8 ignore next */ // covered | ||
}); | ||
/** @summary Flags an element that's ready and able to auto subscribe */ | ||
this.canAutoSubscribe = false; | ||
/** | ||
* `networkStatus` is useful if you want to display a different loading indicator (or no indicator at all) | ||
* depending on your network status as it provides a more detailed view into the state of a network request | ||
* on your component than `loading` does. `networkStatus` is an enum with different number values between 1 and 8. | ||
* These number values each represent a different network state. | ||
* | ||
* 1. `loading`: The query has never been run before and the request is now pending. A query will still have this network status even if a result was returned from the cache, but a query was dispatched anyway. | ||
* 2. `setVariables`: If a query’s variables change and a network request was fired then the network status will be setVariables until the result of that query comes back. React users will see this when options.variables changes on their queries. | ||
* 3. `fetchMore`: Indicates that fetchMore was called on this query and that the network request created is currently in flight. | ||
* 4. `refetch`: It means that refetch was called on a query and the refetch request is currently in flight. | ||
* 5. Unused. | ||
* 6. `poll`: Indicates that a polling query is currently in flight. So for example if you are polling a query every 10 seconds then the network status will switch to poll every 10 seconds whenever a poll request has been sent but not resolved. | ||
* 7. `ready`: No request is in flight for this query, and no errors happened. Everything is OK. | ||
* 8. `error`: No request is in flight for this query, but one or more errors were detected. | ||
* | ||
* If the network status is less then 7 then it is equivalent to `loading` being true. In fact you could | ||
* replace all of your `loading` checks with `networkStatus < 7` and you would not see a difference. | ||
* It is recommended that you use `loading`, however. | ||
*/ | ||
this.networkStatus = NetworkStatus.ready; | ||
/** | ||
* @summary A GraphQL document containing a single query. | ||
*/ | ||
this.query = null; | ||
/** | ||
* If data was read from the cache with missing fields, | ||
* partial will be true. Otherwise, partial will be falsy. | ||
* | ||
* @summary True when the query returned partial data. | ||
*/ | ||
this.partial = false; | ||
/** | ||
* When true, the component will not automatically subscribe to new data. | ||
* Call the `subscribe()` method to do so. | ||
* @attr no-auto-subscribe | ||
*/ | ||
this.noAutoSubscribe = false; | ||
} | ||
constructor() { | ||
super(...arguments); | ||
this.controller = new ApolloQueryBehavior(this, null, { | ||
shouldSubscribe: options => this.readyToReceiveDocument && this.shouldSubscribe(options), | ||
onData: data => this.onData?.(data), | ||
onError: error => this.onError?.(error) | ||
/* c8 ignore next */ | ||
// covered | ||
}); | ||
/** @summary Flags an element that's ready and able to auto subscribe */ | ||
this.canAutoSubscribe = false; | ||
/** | ||
* Determines whether the element should attempt to subscribe i.e. begin querying | ||
* Override to prevent subscribing unless your conditions are met | ||
*/ | ||
shouldSubscribe(options) { | ||
return (void options, true); | ||
} | ||
get options() { | ||
return this.controller.options; | ||
} | ||
set options(v) { | ||
const { onData, onError, shouldSubscribe } = this.controller.options; | ||
this.controller.options = { | ||
onData, onError, shouldSubscribe, ...v, | ||
}; | ||
} | ||
/** | ||
* Exposes the [`ObservableQuery#refetch`](https://www.apollographql.com/docs/react/api/apollo-client.html#ObservableQuery.refetch) method. | ||
* `networkStatus` is useful if you want to display a different loading indicator (or no indicator at all) | ||
* depending on your network status as it provides a more detailed view into the state of a network request | ||
* on your component than `loading` does. `networkStatus` is an enum with different number values between 1 and 8. | ||
* These number values each represent a different network state. | ||
* | ||
* @param variables The new set of variables. If there are missing variables, the previous values of those variables will be used.. | ||
* 1. `loading`: The query has never been run before and the request is now pending. A query will still have this network status even if a result was returned from the cache, but a query was dispatched anyway. | ||
* 2. `setVariables`: If a query’s variables change and a network request was fired then the network status will be setVariables until the result of that query comes back. React users will see this when options.variables changes on their queries. | ||
* 3. `fetchMore`: Indicates that fetchMore was called on this query and that the network request created is currently in flight. | ||
* 4. `refetch`: It means that refetch was called on a query and the refetch request is currently in flight. | ||
* 5. Unused. | ||
* 6. `poll`: Indicates that a polling query is currently in flight. So for example if you are polling a query every 10 seconds then the network status will switch to poll every 10 seconds whenever a poll request has been sent but not resolved. | ||
* 7. `ready`: No request is in flight for this query, and no errors happened. Everything is OK. | ||
* 8. `error`: No request is in flight for this query, but one or more errors were detected. | ||
* | ||
* If the network status is less then 7 then it is equivalent to `loading` being true. In fact you could | ||
* replace all of your `loading` checks with `networkStatus < 7` and you would not see a difference. | ||
* It is recommended that you use `loading`, however. | ||
*/ | ||
async refetch(variables) { | ||
return this.controller.refetch(variables); | ||
} | ||
this.networkStatus = NetworkStatus.ready; | ||
/** | ||
* Resets the observableQuery and subscribes. | ||
* @param params options for controlling how the subscription subscribes | ||
* @summary A GraphQL document containing a single query. | ||
*/ | ||
subscribe(params) { | ||
return this.controller.subscribe(params); | ||
} | ||
this.query = null; | ||
/** | ||
* Lets you pass a GraphQL subscription and updateQuery function | ||
* to subscribe to more updates for your query. | ||
* If data was read from the cache with missing fields, | ||
* partial will be true. Otherwise, partial will be falsy. | ||
* | ||
* The `updateQuery` parameter is a function that takes the previous query data, | ||
* then a `{ subscriptionData: TSubscriptionResult }` object, | ||
* and returns an object with updated query data based on the new results. | ||
* @summary True when the query returned partial data. | ||
*/ | ||
subscribeToMore(options) { | ||
return this.controller.subscribeToMore(options); | ||
} | ||
this.partial = false; | ||
/** | ||
* Executes a Query once and updates the with the result | ||
* When true, the component will not automatically subscribe to new data. | ||
* Call the `subscribe()` method to do so. | ||
* @attr no-auto-subscribe | ||
*/ | ||
async executeQuery(params) { | ||
return this.controller.executeQuery(params); | ||
} | ||
/** | ||
* Exposes the `ObservableQuery#fetchMore` method. | ||
* https://www.apollographql.com/docs/react/api/core/ObservableQuery/#ObservableQuery.fetchMore | ||
* | ||
* The optional `updateQuery` parameter is a function that takes the previous query data, | ||
* then a `{ subscriptionData: TSubscriptionResult }` object, | ||
* and returns an object with updated query data based on the new results. | ||
* | ||
* The optional `variables` parameter is an optional new variables object. | ||
*/ | ||
async fetchMore(params) { | ||
return this.controller.fetchMore(params); | ||
} | ||
startPolling(ms) { | ||
return this.controller.startPolling(ms); | ||
} | ||
stopPolling() { | ||
return this.controller.stopPolling(); | ||
} | ||
this.noAutoSubscribe = false; | ||
} | ||
/** | ||
* Determines whether the element should attempt to subscribe i.e. begin querying | ||
* Override to prevent subscribing unless your conditions are met | ||
*/ | ||
shouldSubscribe(options) { | ||
return void options, true; | ||
} | ||
get options() { | ||
return this.controller.options; | ||
} | ||
set options(v) { | ||
const { | ||
onData, | ||
onError, | ||
shouldSubscribe | ||
} = this.controller.options; | ||
this.controller.options = { | ||
onData, | ||
onError, | ||
shouldSubscribe, | ||
...v | ||
}; | ||
} | ||
/** | ||
* Exposes the [`ObservableQuery#refetch`](https://www.apollographql.com/docs/react/api/apollo-client.html#ObservableQuery.refetch) method. | ||
* | ||
* @param variables The new set of variables. If there are missing variables, the previous values of those variables will be used.. | ||
*/ | ||
async refetch(variables) { | ||
return this.controller.refetch(variables); | ||
} | ||
/** | ||
* Resets the observableQuery and subscribes. | ||
* @param params options for controlling how the subscription subscribes | ||
*/ | ||
subscribe(params) { | ||
return this.controller.subscribe(params); | ||
} | ||
/** | ||
* Lets you pass a GraphQL subscription and updateQuery function | ||
* to subscribe to more updates for your query. | ||
* | ||
* The `updateQuery` parameter is a function that takes the previous query data, | ||
* then a `{ subscriptionData: TSubscriptionResult }` object, | ||
* and returns an object with updated query data based on the new results. | ||
*/ | ||
subscribeToMore(options) { | ||
return this.controller.subscribeToMore(options); | ||
} | ||
/** | ||
* Executes a Query once and updates the with the result | ||
*/ | ||
async executeQuery(params) { | ||
return this.controller.executeQuery(params); | ||
} | ||
/** | ||
* Exposes the `ObservableQuery#fetchMore` method. | ||
* https://www.apollographql.com/docs/react/api/core/ObservableQuery/#ObservableQuery.fetchMore | ||
* | ||
* The optional `updateQuery` parameter is a function that takes the previous query data, | ||
* then a `{ subscriptionData: TSubscriptionResult }` object, | ||
* and returns an object with updated query data based on the new results. | ||
* | ||
* The optional `variables` parameter is an optional new variables object. | ||
*/ | ||
async fetchMore(params) { | ||
return this.controller.fetchMore(params); | ||
} | ||
startPolling(ms) { | ||
return this.controller.startPolling(ms); | ||
} | ||
stopPolling() { | ||
return this.controller.stopPolling(); | ||
} | ||
} | ||
__decorate([ | ||
hosted(), | ||
controlled({ readonly: true }) | ||
], ApolloQuery.prototype, "canAutoSubscribe", void 0); | ||
__decorate([ | ||
hosted(), | ||
controlled(), | ||
attr({ converter: nullableNumberConverter }) | ||
], ApolloQuery.prototype, "networkStatus", void 0); | ||
__decorate([ | ||
hosted(), | ||
controlled() | ||
], ApolloQuery.prototype, "query", void 0); | ||
__decorate([ | ||
hosted(), | ||
controlled() | ||
], ApolloQuery.prototype, "partial", void 0); | ||
__decorate([ | ||
hosted({ path: 'options' }), | ||
controlled({ path: 'options' }), | ||
attr({ mode: 'boolean', attribute: 'partial-refetch' }) | ||
], ApolloQuery.prototype, "partialRefetch", void 0); | ||
__decorate([ | ||
controlled({ path: 'options' }), | ||
attr({ converter: nullableNumberConverter, attribute: 'poll-interval' }) | ||
], ApolloQuery.prototype, "pollInterval", void 0); | ||
__decorate([ | ||
controlled({ path: 'options' }), | ||
attr({ mode: 'boolean', attribute: 'return-partial-data' }) | ||
], ApolloQuery.prototype, "returnPartialData", void 0); | ||
__decorate([ | ||
hosted({ path: 'options' }), | ||
controlled({ path: 'options' }), | ||
attr({ attribute: 'no-auto-subscribe', mode: 'boolean' }) | ||
], ApolloQuery.prototype, "noAutoSubscribe", void 0); | ||
__decorate([ | ||
controlled({ path: 'options' }), | ||
attr({ mode: 'boolean', attribute: 'notify-on-network-status-change' }) | ||
], ApolloQuery.prototype, "notifyOnNetworkStatusChange", void 0); | ||
__decorate([ | ||
hosted({ path: 'options' }), | ||
controlled({ path: 'options' }), | ||
attr({ attribute: 'error-policy' }) | ||
], ApolloQuery.prototype, "errorPolicy", void 0); | ||
__decorate([ | ||
hosted({ path: 'options' }), | ||
controlled({ path: 'options' }), | ||
attr({ attribute: 'fetch-policy' }) | ||
], ApolloQuery.prototype, "fetchPolicy", void 0); | ||
__decorate([ | ||
hosted({ path: 'options' }), | ||
controlled({ path: 'options' }), | ||
attr({ attribute: 'next-fetch-policy' }) | ||
], ApolloQuery.prototype, "nextFetchPolicy", void 0); | ||
__decorate([hosted(), controlled({ | ||
readonly: true | ||
})], ApolloQuery.prototype, "canAutoSubscribe", void 0); | ||
__decorate([hosted(), controlled(), attr({ | ||
converter: nullableNumberConverter | ||
})], ApolloQuery.prototype, "networkStatus", void 0); | ||
__decorate([hosted(), controlled()], ApolloQuery.prototype, "query", void 0); | ||
__decorate([hosted(), controlled()], ApolloQuery.prototype, "partial", void 0); | ||
__decorate([hosted({ | ||
path: 'options' | ||
}), controlled({ | ||
path: 'options' | ||
}), attr({ | ||
mode: 'boolean', | ||
attribute: 'partial-refetch' | ||
})], ApolloQuery.prototype, "partialRefetch", void 0); | ||
__decorate([controlled({ | ||
path: 'options' | ||
}), attr({ | ||
converter: nullableNumberConverter, | ||
attribute: 'poll-interval' | ||
})], ApolloQuery.prototype, "pollInterval", void 0); | ||
__decorate([controlled({ | ||
path: 'options' | ||
}), attr({ | ||
mode: 'boolean', | ||
attribute: 'return-partial-data' | ||
})], ApolloQuery.prototype, "returnPartialData", void 0); | ||
__decorate([hosted({ | ||
path: 'options' | ||
}), controlled({ | ||
path: 'options' | ||
}), attr({ | ||
attribute: 'no-auto-subscribe', | ||
mode: 'boolean' | ||
})], ApolloQuery.prototype, "noAutoSubscribe", void 0); | ||
__decorate([controlled({ | ||
path: 'options' | ||
}), attr({ | ||
mode: 'boolean', | ||
attribute: 'notify-on-network-status-change' | ||
})], ApolloQuery.prototype, "notifyOnNetworkStatusChange", void 0); | ||
__decorate([hosted({ | ||
path: 'options' | ||
}), controlled({ | ||
path: 'options' | ||
}), attr({ | ||
attribute: 'error-policy' | ||
})], ApolloQuery.prototype, "errorPolicy", void 0); | ||
__decorate([hosted({ | ||
path: 'options' | ||
}), controlled({ | ||
path: 'options' | ||
}), attr({ | ||
attribute: 'fetch-policy' | ||
})], ApolloQuery.prototype, "fetchPolicy", void 0); | ||
__decorate([hosted({ | ||
path: 'options' | ||
}), controlled({ | ||
path: 'options' | ||
}), attr({ | ||
attribute: 'next-fetch-policy' | ||
})], ApolloQuery.prototype, "nextFetchPolicy", void 0); | ||
//# sourceMappingURL=apollo-query.js.map |
@@ -10,4 +10,4 @@ import { __decorate } from "tslib"; | ||
import * as S from '@apollo-elements/test/schema'; | ||
import { assertType, isApolloError, setupSpies, setupStubs, stringify, } from '@apollo-elements/test'; | ||
const template = html ` | ||
import { assertType, isApolloError, setupSpies, setupStubs, stringify } from '@apollo-elements/test'; | ||
const template = html` | ||
<output id="data">${x => stringify(x.data)}</output> | ||
@@ -20,152 +20,171 @@ <output id="error">${x => stringify(x.error)}</output> | ||
let TestableApolloQuery = class TestableApolloQuery extends ApolloQuery { | ||
async hasRendered() { | ||
await DOM.nextUpdate(); | ||
return this; | ||
} | ||
$(id) { | ||
return this.shadowRoot.getElementById(id); | ||
} | ||
async hasRendered() { | ||
await DOM.nextUpdate(); | ||
return this; | ||
} | ||
$(id) { | ||
return this.shadowRoot.getElementById(id); | ||
} | ||
}; | ||
TestableApolloQuery = __decorate([ | ||
customElement({ name: 'fast-testable-apollo-query-class', template }) | ||
], TestableApolloQuery); | ||
TestableApolloQuery = __decorate([customElement({ | ||
name: 'fast-testable-apollo-query-class', | ||
template | ||
})], TestableApolloQuery); | ||
let counter = -1; | ||
describe('[FAST] ApolloQuery', function () { | ||
describeQuery({ | ||
async setupFunction(opts) { | ||
const name = `fast-setup-function-element-${counter++}`; | ||
let Test = class Test extends TestableApolloQuery { | ||
}; | ||
Test = __decorate([ | ||
customElement({ name, template }) | ||
], Test); | ||
const attrs = opts?.attributes ? ` ${opts.attributes}` : ''; | ||
const innerHTML = opts?.innerHTML ?? ''; | ||
const spies = setupSpies(opts?.spy, Test.prototype); | ||
const stubs = setupStubs(opts?.stub, Test.prototype); | ||
const element = await fixture(`<${name}${attrs}>${innerHTML}</${name}>`); | ||
for (const [key, val] of Object.entries(opts?.properties ?? {})) | ||
element[key] = val; | ||
await DOM.nextUpdate(); | ||
return { element, spies, stubs }; | ||
}, | ||
describeQuery({ | ||
async setupFunction(opts) { | ||
const name = `fast-setup-function-element-${counter++}`; | ||
let Test = class Test extends TestableApolloQuery {}; | ||
Test = __decorate([customElement({ | ||
name, | ||
template | ||
})], Test); | ||
const attrs = opts?.attributes ? ` ${opts.attributes}` : ''; | ||
const innerHTML = opts?.innerHTML ?? ''; | ||
const spies = setupSpies(opts?.spy, Test.prototype); | ||
const stubs = setupStubs(opts?.stub, Test.prototype); | ||
const element = await fixture(`<${name}${attrs}>${innerHTML}</${name}>`); | ||
for (const [key, val] of Object.entries(opts?.properties ?? {})) element[key] = val; | ||
await DOM.nextUpdate(); | ||
return { | ||
element, | ||
spies, | ||
stubs | ||
}; | ||
} | ||
}); | ||
describe('subclassing', function () { | ||
it('is an instance of FASTElement', async function () { | ||
const name = 'is-an-instance-of-f-a-s-t-element'; | ||
let Test = class Test extends ApolloQuery {}; | ||
Test = __decorate([customElement({ | ||
name | ||
})], Test); | ||
const tag = unsafeStatic(name); | ||
const el = await fixture(h`<${tag}></${tag}>`); | ||
expect(el).to.be.an.instanceOf(FASTElement); | ||
}); | ||
describe('subclassing', function () { | ||
it('is an instance of FASTElement', async function () { | ||
const name = 'is-an-instance-of-f-a-s-t-element'; | ||
let Test = class Test extends ApolloQuery { | ||
}; | ||
Test = __decorate([ | ||
customElement({ name }) | ||
], Test); | ||
const tag = unsafeStatic(name); | ||
const el = await fixture(h `<${tag}></${tag}>`); | ||
expect(el).to.be.an.instanceOf(FASTElement); | ||
}); | ||
}); | ||
it('renders when data is set', async function rendersOnData() { | ||
const name = 'renders-when-data-is-set'; | ||
const template = html`${x => x.data?.foo ?? 'FAIL'}`; | ||
let Test = class Test extends ApolloQuery {}; | ||
Test = __decorate([customElement({ | ||
name, | ||
template | ||
})], Test); | ||
const tag = unsafeStatic(name); | ||
const element = await fixture(h`<${tag} .data="${{ | ||
foo: 'bar' | ||
}}"></${tag}>`); | ||
expect(element).shadowDom.to.equal('bar'); | ||
}); | ||
describe('polling', function () { | ||
const name = 'polling-and-timers'; | ||
let Test = class Test extends ApolloQuery { | ||
constructor() { | ||
super(...arguments); | ||
this.query = S.NullableParamQuery; | ||
} | ||
}; | ||
Test = __decorate([customElement({ | ||
name | ||
})], Test); | ||
let element; | ||
let clock; | ||
beforeEach(async function () { | ||
element = await fixture(`<${name}></${name}>`); | ||
element.client = makeClient(); | ||
}); | ||
it('renders when data is set', async function rendersOnData() { | ||
const name = 'renders-when-data-is-set'; | ||
const template = html `${x => x.data?.foo ?? 'FAIL'}`; | ||
let Test = class Test extends ApolloQuery { | ||
}; | ||
Test = __decorate([ | ||
customElement({ name, template }) | ||
], Test); | ||
const tag = unsafeStatic(name); | ||
const element = await fixture(h `<${tag} .data="${{ foo: 'bar' }}"></${tag}>`); | ||
expect(element).shadowDom.to.equal('bar'); | ||
beforeEach(() => spy(element.controller, 'refetch')); | ||
beforeEach(() => { | ||
clock = useFakeTimers(); | ||
}); | ||
describe('polling', function () { | ||
const name = 'polling-and-timers'; | ||
let Test = class Test extends ApolloQuery { | ||
constructor() { | ||
super(...arguments); | ||
this.query = S.NullableParamQuery; | ||
} | ||
}; | ||
Test = __decorate([ | ||
customElement({ name }) | ||
], Test); | ||
let element; | ||
let clock; | ||
beforeEach(async function () { | ||
element = await fixture(`<${name}></${name}>`); | ||
element.client = makeClient(); | ||
afterEach(() => clock.restore()); | ||
afterEach(() => { | ||
element.controller.refetch.restore?.(); | ||
}); | ||
describe('calling startPolling(1000)', function () { | ||
beforeEach(function startPolling() { | ||
element.startPolling(1000); | ||
}); | ||
beforeEach(() => { | ||
clock.tick(3500); | ||
}); | ||
it('refetches', function () { | ||
expect(element.controller.refetch).to.have.been.calledThrice; | ||
}); | ||
describe('then stopPolling', function () { | ||
beforeEach(function stopPolling() { | ||
element.stopPolling(); | ||
}); | ||
beforeEach(() => spy(element.controller, 'refetch')); | ||
beforeEach(() => { | ||
clock = useFakeTimers(); | ||
clock.tick(3500); | ||
}); | ||
afterEach(() => clock.restore()); | ||
afterEach(() => { | ||
element.controller.refetch.restore?.(); | ||
it('stops calling refetch', function () { | ||
expect(element.controller.refetch).to.have.been.calledThrice; | ||
}); | ||
describe('calling startPolling(1000)', function () { | ||
beforeEach(function startPolling() { element.startPolling(1000); }); | ||
beforeEach(() => { | ||
clock.tick(3500); | ||
}); | ||
it('refetches', function () { | ||
expect(element.controller.refetch).to.have.been.calledThrice; | ||
}); | ||
describe('then stopPolling', function () { | ||
beforeEach(function stopPolling() { element.stopPolling(); }); | ||
beforeEach(() => { clock.tick(3500); }); | ||
it('stops calling refetch', function () { | ||
expect(element.controller.refetch).to.have.been.calledThrice; | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
class TypeCheck extends ApolloQuery { | ||
typeCheck() { | ||
/* eslint-disable max-len, func-call-spacing, no-multi-spaces */ | ||
assertType(this); | ||
assertType(this); | ||
// ApolloElementInterface | ||
assertType(this.client); | ||
assertType(this.context); | ||
assertType(this.loading); | ||
assertType(this.document); | ||
assertType(this.error); | ||
assertType(this.errors); | ||
assertType(this.data); | ||
assertType(this.error.message); | ||
assertType(this.data.a); | ||
assertType(this.data.b); | ||
if (isApolloError(this.error)) | ||
assertType(this.error.graphQLErrors); | ||
// ApolloQueryInterface | ||
assertType(this.query); | ||
assertType(this.variables); | ||
assertType(this.errorPolicy); | ||
assertType(this.errorPolicy); | ||
// @ts-expect-error: ErrorPolicy is not a number | ||
assertType(this.errorPolicy); | ||
assertType(this.fetchPolicy); | ||
assertType(this.fetchPolicy); | ||
if (typeof this.nextFetchPolicy !== 'function') | ||
assertType(this.nextFetchPolicy); | ||
assertType(this.networkStatus); | ||
assertType(this.networkStatus); | ||
// @ts-expect-error: NetworkStatus is not a string | ||
assertType(this.networkStatus); | ||
assertType(this.notifyOnNetworkStatusChange); | ||
assertType(this.pollInterval); | ||
assertType(this.partial); | ||
assertType(this.partialRefetch); | ||
assertType(this.returnPartialData); | ||
assertType(this.noAutoSubscribe); | ||
assertType(this.options); | ||
/* eslint-enable max-len, func-call-spacing, no-multi-spaces */ | ||
} | ||
typeCheck() { | ||
/* eslint-disable max-len, func-call-spacing, no-multi-spaces */ | ||
assertType(this); | ||
assertType(this); // ApolloElementInterface | ||
assertType(this.client); | ||
assertType(this.context); | ||
assertType(this.loading); | ||
assertType(this.document); | ||
assertType(this.error); | ||
assertType(this.errors); | ||
assertType(this.data); | ||
assertType(this.error.message); | ||
assertType(this.data.a); | ||
assertType(this.data.b); | ||
if (isApolloError(this.error)) assertType(this.error.graphQLErrors); // ApolloQueryInterface | ||
assertType(this.query); | ||
assertType(this.variables); | ||
assertType(this.errorPolicy); | ||
assertType(this.errorPolicy); // @ts-expect-error: ErrorPolicy is not a number | ||
assertType(this.errorPolicy); | ||
assertType(this.fetchPolicy); | ||
assertType(this.fetchPolicy); | ||
if (typeof this.nextFetchPolicy !== 'function') assertType(this.nextFetchPolicy); | ||
assertType(this.networkStatus); | ||
assertType(this.networkStatus); // @ts-expect-error: NetworkStatus is not a string | ||
assertType(this.networkStatus); | ||
assertType(this.notifyOnNetworkStatusChange); | ||
assertType(this.pollInterval); | ||
assertType(this.partial); | ||
assertType(this.partialRefetch); | ||
assertType(this.returnPartialData); | ||
assertType(this.noAutoSubscribe); | ||
assertType(this.options); | ||
/* eslint-enable max-len, func-call-spacing, no-multi-spaces */ | ||
} | ||
} | ||
class TDNTypeCheck extends ApolloQuery { | ||
typeCheck() { | ||
assertType(this.data); | ||
assertType(this.variables); | ||
assertType(this.query); | ||
} | ||
typeCheck() { | ||
assertType(this.data); | ||
assertType(this.variables); | ||
assertType(this.query); | ||
} | ||
} | ||
//# sourceMappingURL=apollo-query.test.js.map |
@@ -17,90 +17,130 @@ import { __decorate } from "tslib"; | ||
*/ | ||
export class ApolloSubscription extends ApolloElement { | ||
constructor() { | ||
super(...arguments); | ||
this.controller = new ApolloSubscriptionBehavior(this, null, { | ||
shouldSubscribe: x => this.readyToReceiveDocument && this.shouldSubscribe(x), | ||
onData: data => this.onSubscriptionData?.(data), | ||
onComplete: () => this.onSubscriptionComplete?.(), | ||
onError: error => this.onError?.(error), | ||
}); | ||
/** | ||
* @summary A GraphQL document containing a single subscription. | ||
*/ | ||
this.subscription = null; | ||
/** | ||
* @summary If true, the element will not begin querying data until you manually call `subscribe` | ||
* @attr no-auto-subscribe | ||
*/ | ||
this.noAutoSubscribe = false; | ||
/** | ||
* @summary Determines if your subscription should be unsubscribed and subscribed again. | ||
*/ | ||
this.shouldResubscribe = false; | ||
/** | ||
* @summary If true, the query will be skipped entirely | ||
*/ | ||
this.skip = false; | ||
} | ||
/** @summary Flags an element that's ready and able to auto subscribe */ | ||
get canAutoSubscribe() { return this.controller?.canAutoSubscribe ?? false; } | ||
constructor() { | ||
super(...arguments); | ||
this.controller = new ApolloSubscriptionBehavior(this, null, { | ||
shouldSubscribe: x => this.readyToReceiveDocument && this.shouldSubscribe(x), | ||
onData: data => this.onSubscriptionData?.(data), | ||
onComplete: () => this.onSubscriptionComplete?.(), | ||
onError: error => this.onError?.(error) | ||
}); | ||
/** | ||
* @summary Resets the observable and subscribes. | ||
* @summary A GraphQL document containing a single subscription. | ||
*/ | ||
subscribe(...args) { | ||
return this.controller.subscribe(...args); | ||
} | ||
this.subscription = null; | ||
/** | ||
* @summary Cancels and clears the subscription | ||
* @summary If true, the element will not begin querying data until you manually call `subscribe` | ||
* @attr no-auto-subscribe | ||
*/ | ||
cancel() { | ||
return this.controller.cancel(); | ||
} | ||
this.noAutoSubscribe = false; | ||
/** | ||
* Determines whether the element should attempt to subscribe automatically | ||
* Override to prevent subscribing unless your conditions are met | ||
* @summary Determines if your subscription should be unsubscribed and subscribed again. | ||
*/ | ||
shouldSubscribe(options) { | ||
return (void options, true); | ||
} | ||
this.shouldResubscribe = false; | ||
/** | ||
* @summary If true, the query will be skipped entirely | ||
*/ | ||
this.skip = false; | ||
} | ||
/** @summary Flags an element that's ready and able to auto subscribe */ | ||
get canAutoSubscribe() { | ||
return this.controller?.canAutoSubscribe ?? false; | ||
} | ||
/** | ||
* @summary Resets the observable and subscribes. | ||
*/ | ||
subscribe(...args) { | ||
return this.controller.subscribe(...args); | ||
} | ||
/** | ||
* @summary Cancels and clears the subscription | ||
*/ | ||
cancel() { | ||
return this.controller.cancel(); | ||
} | ||
/** | ||
* Determines whether the element should attempt to subscribe automatically | ||
* Override to prevent subscribing unless your conditions are met | ||
*/ | ||
shouldSubscribe(options) { | ||
return void options, true; | ||
} | ||
} | ||
__decorate([ | ||
hosted(), | ||
controlled() | ||
], ApolloSubscription.prototype, "subscription", void 0); | ||
__decorate([ | ||
hosted({ path: 'options' }), | ||
controlled({ path: 'options' }), | ||
attr({ mode: 'boolean', attribute: 'no-auto-subscribe' }) | ||
], ApolloSubscription.prototype, "noAutoSubscribe", void 0); | ||
__decorate([ | ||
hosted({ path: 'options' }), | ||
controlled({ path: 'options' }), | ||
attr({ mode: 'boolean', attribute: 'notify-on-network-status-change' }) | ||
], ApolloSubscription.prototype, "notifyOnNetworkStatusChange", void 0); | ||
__decorate([ | ||
hosted({ path: 'options' }), | ||
controlled({ path: 'options' }), | ||
attr({ mode: 'boolean', attribute: 'should-resubscribe' }) | ||
], ApolloSubscription.prototype, "shouldResubscribe", void 0); | ||
__decorate([ | ||
hosted({ path: 'options' }), | ||
controlled({ path: 'options' }), | ||
attr({ mode: 'boolean', attribute: 'skip' }) | ||
], ApolloSubscription.prototype, "skip", void 0); | ||
__decorate([ | ||
hosted({ path: 'options' }), | ||
controlled({ path: 'options' }), | ||
attr({ attribute: 'error-policy' }) | ||
], ApolloSubscription.prototype, "errorPolicy", void 0); | ||
__decorate([ | ||
hosted({ path: 'options' }), | ||
controlled({ path: 'options' }), | ||
attr({ attribute: 'fetch-policy' }) | ||
], ApolloSubscription.prototype, "fetchPolicy", void 0); | ||
__decorate([ | ||
hosted({ path: 'options' }), | ||
controlled({ path: 'options' }), | ||
attr({ converter: nullableNumberConverter, attribute: 'poll-interval' }) | ||
], ApolloSubscription.prototype, "pollInterval", void 0); | ||
__decorate([hosted(), controlled()], ApolloSubscription.prototype, "subscription", void 0); | ||
__decorate([hosted({ | ||
path: 'options' | ||
}), controlled({ | ||
path: 'options' | ||
}), attr({ | ||
mode: 'boolean', | ||
attribute: 'no-auto-subscribe' | ||
})], ApolloSubscription.prototype, "noAutoSubscribe", void 0); | ||
__decorate([hosted({ | ||
path: 'options' | ||
}), controlled({ | ||
path: 'options' | ||
}), attr({ | ||
mode: 'boolean', | ||
attribute: 'notify-on-network-status-change' | ||
})], ApolloSubscription.prototype, "notifyOnNetworkStatusChange", void 0); | ||
__decorate([hosted({ | ||
path: 'options' | ||
}), controlled({ | ||
path: 'options' | ||
}), attr({ | ||
mode: 'boolean', | ||
attribute: 'should-resubscribe' | ||
})], ApolloSubscription.prototype, "shouldResubscribe", void 0); | ||
__decorate([hosted({ | ||
path: 'options' | ||
}), controlled({ | ||
path: 'options' | ||
}), attr({ | ||
mode: 'boolean', | ||
attribute: 'skip' | ||
})], ApolloSubscription.prototype, "skip", void 0); | ||
__decorate([hosted({ | ||
path: 'options' | ||
}), controlled({ | ||
path: 'options' | ||
}), attr({ | ||
attribute: 'error-policy' | ||
})], ApolloSubscription.prototype, "errorPolicy", void 0); | ||
__decorate([hosted({ | ||
path: 'options' | ||
}), controlled({ | ||
path: 'options' | ||
}), attr({ | ||
attribute: 'fetch-policy' | ||
})], ApolloSubscription.prototype, "fetchPolicy", void 0); | ||
__decorate([hosted({ | ||
path: 'options' | ||
}), controlled({ | ||
path: 'options' | ||
}), attr({ | ||
converter: nullableNumberConverter, | ||
attribute: 'poll-interval' | ||
})], ApolloSubscription.prototype, "pollInterval", void 0); | ||
//# sourceMappingURL=apollo-subscription.js.map |
import { __decorate } from "tslib"; | ||
import * as S from '@apollo-elements/test/schema'; | ||
import { setupClient, setupSpies, setupStubs, stringify, teardownClient, } from '@apollo-elements/test'; | ||
import { setupClient, setupSpies, setupStubs, stringify, teardownClient } from '@apollo-elements/test'; | ||
import { expect, fixture } from '@open-wc/testing'; | ||
@@ -10,3 +10,3 @@ import { html as h, unsafeStatic } from 'lit/static-html.js'; | ||
import { ApolloSubscription } from './apollo-subscription'; | ||
const template = html ` | ||
const template = html` | ||
<output id="data">${x => stringify(x.data)}</output> | ||
@@ -17,115 +17,132 @@ <output id="error">${x => stringify(x.error)}</output> | ||
let TestableApolloSubscription = class TestableApolloSubscription extends ApolloSubscription { | ||
async hasRendered() { | ||
await DOM.nextUpdate(); | ||
return this; | ||
} | ||
$(id) { | ||
return this.shadowRoot.getElementById(id); | ||
} | ||
async hasRendered() { | ||
await DOM.nextUpdate(); | ||
return this; | ||
} | ||
$(id) { | ||
return this.shadowRoot.getElementById(id); | ||
} | ||
}; | ||
TestableApolloSubscription = __decorate([ | ||
customElement({ name: 'testable-apollo-subscription', template }) | ||
], TestableApolloSubscription); | ||
TestableApolloSubscription = __decorate([customElement({ | ||
name: 'testable-apollo-subscription', | ||
template | ||
})], TestableApolloSubscription); | ||
let counter = 1; | ||
describe('[FAST] ApolloSubscription', function () { | ||
describeSubscription({ | ||
async setupFunction(opts) { | ||
const name = `fast-setup-function-element-${counter++}`; | ||
let Test = class Test extends TestableApolloSubscription { | ||
}; | ||
Test = __decorate([ | ||
customElement({ name, template }) | ||
], Test); | ||
const attrs = opts?.attributes ? ` ${opts.attributes}` : ''; | ||
const innerHTML = opts?.innerHTML ?? ''; | ||
const spies = setupSpies(opts?.spy, Test.prototype); | ||
const stubs = setupStubs(opts?.stub, Test.prototype); | ||
const element = await fixture(`<${name}${attrs}>${innerHTML}</${name}>`); | ||
for (const [key, val] of Object.entries(opts?.properties ?? {})) | ||
element[key] = val; | ||
await DOM.nextUpdate(); | ||
return { element, spies, stubs }; | ||
}, | ||
describeSubscription({ | ||
async setupFunction(opts) { | ||
const name = `fast-setup-function-element-${counter++}`; | ||
let Test = class Test extends TestableApolloSubscription {}; | ||
Test = __decorate([customElement({ | ||
name, | ||
template | ||
})], Test); | ||
const attrs = opts?.attributes ? ` ${opts.attributes}` : ''; | ||
const innerHTML = opts?.innerHTML ?? ''; | ||
const spies = setupSpies(opts?.spy, Test.prototype); | ||
const stubs = setupStubs(opts?.stub, Test.prototype); | ||
const element = await fixture(`<${name}${attrs}>${innerHTML}</${name}>`); | ||
for (const [key, val] of Object.entries(opts?.properties ?? {})) element[key] = val; | ||
await DOM.nextUpdate(); | ||
return { | ||
element, | ||
spies, | ||
stubs | ||
}; | ||
} | ||
}); | ||
describe('subclassing', function () { | ||
it('is an instance of FASTElement', async function () { | ||
const name = 'is-an-instance-of-f-a-s-t-element'; | ||
let Klass = class Klass extends TestableApolloSubscription {}; | ||
Klass = __decorate([customElement({ | ||
name | ||
})], Klass); | ||
const el = await fixture(`<${name}></${name}>`); | ||
expect(el).to.be.an.instanceOf(FASTElement); | ||
}); | ||
describe('subclassing', function () { | ||
it('is an instance of FASTElement', async function () { | ||
const name = 'is-an-instance-of-f-a-s-t-element'; | ||
let Klass = class Klass extends TestableApolloSubscription { | ||
}; | ||
Klass = __decorate([ | ||
customElement({ name }) | ||
], Klass); | ||
const el = await fixture(`<${name}></${name}>`); | ||
expect(el).to.be.an.instanceOf(FASTElement); | ||
}); | ||
it('renders when data is set', async function rendersOnData() { | ||
const name = 'renders-when-data-is-set'; | ||
const template = html `${x => x.data?.foo ?? 'FAIL'}`; | ||
let Test = class Test extends ApolloSubscription { | ||
}; | ||
Test = __decorate([ | ||
customElement({ name, template }) | ||
], Test); | ||
const tag = unsafeStatic(name); | ||
const element = await fixture(h `<${tag} .data="${{ foo: 'bar' }}"></${tag}>`); | ||
expect(element).shadowDom.to.equal('bar'); | ||
}); | ||
it('renders on error', async function () { | ||
setupClient(); | ||
const name = 'renders-on-error'; | ||
const template = html `${x => x.error?.message ?? 'FAIL'}`; | ||
let Test = class Test extends ApolloSubscription { | ||
constructor() { | ||
super(...arguments); | ||
this.subscription = S.NullableParamSubscription; | ||
this.variables = { nullable: 'error' }; | ||
} | ||
}; | ||
Test = __decorate([ | ||
customElement({ name, template }) | ||
], Test); | ||
const tag = unsafeStatic(name); | ||
const element = await fixture(h `<${tag}></${tag}>`); | ||
expect(element.shadowRoot?.textContent).to.be.ok.and.to.not.contain('FAIL'); | ||
teardownClient(); | ||
}); | ||
it('renders when data is set', async function rendersOnData() { | ||
const name = 'renders-when-data-is-set'; | ||
const template = html`${x => x.data?.foo ?? 'FAIL'}`; | ||
let Test = class Test extends ApolloSubscription {}; | ||
Test = __decorate([customElement({ | ||
name, | ||
template | ||
})], Test); | ||
const tag = unsafeStatic(name); | ||
const element = await fixture(h`<${tag} .data="${{ | ||
foo: 'bar' | ||
}}"></${tag}>`); | ||
expect(element).shadowDom.to.equal('bar'); | ||
}); | ||
it('renders on error', async function () { | ||
setupClient(); | ||
const name = 'renders-on-error'; | ||
const template = html`${x => x.error?.message ?? 'FAIL'}`; | ||
let Test = class Test extends ApolloSubscription { | ||
constructor() { | ||
super(...arguments); | ||
this.subscription = S.NullableParamSubscription; | ||
this.variables = { | ||
nullable: 'error' | ||
}; | ||
} | ||
}; | ||
Test = __decorate([customElement({ | ||
name, | ||
template | ||
})], Test); | ||
const tag = unsafeStatic(name); | ||
const element = await fixture(h`<${tag}></${tag}>`); | ||
expect(element.shadowRoot?.textContent).to.be.ok.and.to.not.contain('FAIL'); | ||
teardownClient(); | ||
}); | ||
}); | ||
}); | ||
class TypeCheck extends ApolloSubscription { | ||
typeCheck() { | ||
/* eslint-disable max-len, func-call-spacing, no-multi-spaces */ | ||
assertType(this); | ||
assertType(this); | ||
// ApolloElementInterface | ||
assertType(this.client); | ||
assertType(this.context); | ||
assertType(this.loading); | ||
assertType(this.document); | ||
assertType(this.error); | ||
assertType(this.errors); | ||
assertType(this.data); | ||
assertType(this.error.message); | ||
assertType(this.data.a); | ||
// @ts-expect-error: b as number type | ||
assertType(this.data.b); | ||
if (isApolloError(this.error)) | ||
assertType(this.error.graphQLErrors); | ||
// ApolloSubscriptionInterface | ||
assertType(this.subscription); | ||
assertType(this.variables); | ||
assertType(this.fetchPolicy); | ||
assertType(this.fetchPolicy); | ||
assertType(this.notifyOnNetworkStatusChange); | ||
assertType(this.pollInterval); | ||
assertType(this.skip); | ||
assertType(this.noAutoSubscribe); | ||
/* eslint-enable max-len, func-call-spacing, no-multi-spaces */ | ||
} | ||
typeCheck() { | ||
/* eslint-disable max-len, func-call-spacing, no-multi-spaces */ | ||
assertType(this); | ||
assertType(this); // ApolloElementInterface | ||
assertType(this.client); | ||
assertType(this.context); | ||
assertType(this.loading); | ||
assertType(this.document); | ||
assertType(this.error); | ||
assertType(this.errors); | ||
assertType(this.data); | ||
assertType(this.error.message); | ||
assertType(this.data.a); // @ts-expect-error: b as number type | ||
assertType(this.data.b); | ||
if (isApolloError(this.error)) assertType(this.error.graphQLErrors); // ApolloSubscriptionInterface | ||
assertType(this.subscription); | ||
assertType(this.variables); | ||
assertType(this.fetchPolicy); | ||
assertType(this.fetchPolicy); | ||
assertType(this.notifyOnNetworkStatusChange); | ||
assertType(this.pollInterval); | ||
assertType(this.skip); | ||
assertType(this.noAutoSubscribe); | ||
/* eslint-enable max-len, func-call-spacing, no-multi-spaces */ | ||
} | ||
} | ||
class TDNTypeCheck extends ApolloSubscription { | ||
typeCheck() { | ||
assertType(this.data); | ||
assertType(this.variables); | ||
} | ||
typeCheck() { | ||
assertType(this.data); | ||
assertType(this.variables); | ||
} | ||
} | ||
//# sourceMappingURL=apollo-subscription.test.js.map |
import { Observable } from '@microsoft/fast-element'; | ||
export function hosted(opts) { | ||
return function (target, key) { | ||
const descriptor = Object.getOwnPropertyDescriptor(target, key); | ||
const { get, set } = descriptor ?? {}; /* c8 ignore next */ | ||
if (!get || !set) | ||
throw new Error(`${key} not described; call @controlled first`); /* c8 ignore next */ | ||
Object.defineProperty(target, key, { | ||
get() { | ||
Observable.track(this, key); | ||
return get.call(this); | ||
}, | ||
set(v) { | ||
set.call(this, v); | ||
Observable.notify(this, key); | ||
}, | ||
}); | ||
Object.defineProperty(target, `${key}Changed`, { | ||
value() { | ||
if (!this.controller) | ||
return; /* c8 ignore next */ // covered | ||
if (opts?.path) | ||
this.controller[opts.path][key] = this[key]; /* c8 ignore next */ // covered | ||
else | ||
this.controller[key] = this[key]; | ||
}, | ||
}); | ||
}; | ||
return function (target, key) { | ||
const descriptor = Object.getOwnPropertyDescriptor(target, key); | ||
const { | ||
get, | ||
set | ||
} = descriptor ?? {}; | ||
/* c8 ignore next */ | ||
if (!get || !set) throw new Error(`${key} not described; call @controlled first`); | ||
/* c8 ignore next */ | ||
Object.defineProperty(target, key, { | ||
get() { | ||
Observable.track(this, key); | ||
return get.call(this); | ||
}, | ||
set(v) { | ||
set.call(this, v); | ||
Observable.notify(this, key); | ||
} | ||
}); | ||
Object.defineProperty(target, `${key}Changed`, { | ||
value() { | ||
if (!this.controller) return; | ||
/* c8 ignore next */ | ||
// covered | ||
if (opts?.path) this.controller[opts.path][key] = this[key]; | ||
/* c8 ignore next */ | ||
// covered | ||
else this.controller[key] = this[key]; | ||
} | ||
}); | ||
}; | ||
} | ||
//# sourceMappingURL=decorators.js.map |
@@ -5,16 +5,17 @@ import { __decorate } from "tslib"; | ||
describe('[FAST] @hosted', function () { | ||
it('throws if misused', function () { | ||
expect(() => { | ||
class A { | ||
constructor() { | ||
this.a = 'a'; | ||
} | ||
} | ||
__decorate([ | ||
hosted() | ||
], A.prototype, "a", void 0); | ||
A; | ||
}).to.throw('a not described; call @controlled first'); | ||
}); | ||
it('throws if misused', function () { | ||
expect(() => { | ||
class A { | ||
constructor() { | ||
this.a = 'a'; | ||
} | ||
} | ||
__decorate([hosted()], A.prototype, "a", void 0); | ||
A; | ||
}).to.throw('a not described; call @controlled first'); | ||
}); | ||
}); | ||
//# sourceMappingURL=decorators.test.js.map |
import { DOM } from '@microsoft/fast-element'; | ||
const hosts = new WeakMap(); | ||
export class FASTControllerHost { | ||
constructor($fastElement) { | ||
this.$fastElement = $fastElement; | ||
this.#controllers = new Set(); | ||
if (hosts.has($fastElement)) | ||
return hosts.get($fastElement); | ||
else | ||
hosts.set($fastElement, this); | ||
} | ||
#controllers; | ||
addController(controller) { this.#controllers.add(controller); } | ||
removeController(controller) { this.#controllers.delete(controller); } | ||
/** Shouldn't need an implementation, since FAST's reactivity model is pull-based */ | ||
requestUpdate() { null; } | ||
get updateComplete() { | ||
return DOM.nextUpdate().then(() => true); | ||
} | ||
constructor($fastElement) { | ||
this.$fastElement = $fastElement; | ||
this.#controllers = new Set(); | ||
if (hosts.has($fastElement)) return hosts.get($fastElement);else hosts.set($fastElement, this); | ||
} | ||
#controllers; | ||
addController(controller) { | ||
this.#controllers.add(controller); | ||
} | ||
removeController(controller) { | ||
this.#controllers.delete(controller); | ||
} | ||
/** Shouldn't need an implementation, since FAST's reactivity model is pull-based */ | ||
requestUpdate() { | ||
null; | ||
} | ||
get updateComplete() { | ||
return DOM.nextUpdate().then(() => true); | ||
} | ||
} | ||
//# sourceMappingURL=fast-controller-host.js.map |
@@ -7,17 +7,18 @@ import { __decorate } from "tslib"; | ||
describe('[FAST] FASTControllerHost', function () { | ||
it('reuses instances', async function () { | ||
let A = class A extends FASTElement { | ||
constructor() { | ||
super(...arguments); | ||
this.b = new ApolloQueryBehavior(this); | ||
this.c = new ApolloQueryBehavior(this); | ||
} | ||
}; | ||
A = __decorate([ | ||
customElement({ name: 'a-l' }) | ||
], A); | ||
const el = await fixture('<a-l></a-l>'); | ||
expect(el.b.host).to.equal(el.c.host).and.to.be.an.instanceof(FASTControllerHost); | ||
}); | ||
it('reuses instances', async function () { | ||
let A = class A extends FASTElement { | ||
constructor() { | ||
super(...arguments); | ||
this.b = new ApolloQueryBehavior(this); | ||
this.c = new ApolloQueryBehavior(this); | ||
} | ||
}; | ||
A = __decorate([customElement({ | ||
name: 'a-l' | ||
})], A); | ||
const el = await fixture('<a-l></a-l>'); | ||
expect(el.b.host).to.equal(el.c.host).and.to.be.an.instanceof(FASTControllerHost); | ||
}); | ||
}); | ||
//# sourceMappingURL=fast-controller-host.test.js.map |
{ | ||
"name": "@apollo-elements/fast", | ||
"version": "3.0.2", | ||
"version": "3.0.3", | ||
"description": "👩🚀🌛 FastElements for Apollo GraphQL 🚀👨🚀", | ||
@@ -10,22 +10,7 @@ "main": "index.js", | ||
"exports": { | ||
".": { | ||
"esbuild": "./index.ts", | ||
"default": "./index.js" | ||
}, | ||
"./*": { | ||
"esbuild": "./*.ts", | ||
"default": "./*.js" | ||
}, | ||
"./*.js": { | ||
"esbuild": "./*.ts", | ||
"default": "./*.js" | ||
}, | ||
"./bases/*": { | ||
"esbuild": "./bases/*.ts", | ||
"default": "./bases/*.js" | ||
}, | ||
"./bases/*.js": { | ||
"esbuild": "./bases/*.ts", | ||
"default": "./bases/*.js" | ||
} | ||
".": "./index.js", | ||
"./*": "./*.js", | ||
"./*.js": "./*.js", | ||
"./bases/*": "./bases/*.js", | ||
"./bases/*.js": "./bases/*.js" | ||
}, | ||
@@ -42,5 +27,7 @@ "files": [ | ||
"scripts": { | ||
"prepublishOnly": "npm run build", | ||
"build": "tsc -b .", | ||
"prepublishOnly": "npm run analyze && npm run build", | ||
"analyze": "custom-elements-manifest analyze --fast", | ||
"build": "run-s build:*", | ||
"build:tsc": "tsc -b .", | ||
"build:babel": "babel --source-maps --ignore '*.config.js' --plugins @babel/plugin-proposal-class-static-block --out-dir . .", | ||
"test": "wtr --coverage --config ../../web-test-runner.config.js --root-dir '../..' './*.test.ts'" | ||
@@ -68,4 +55,4 @@ }, | ||
"dependencies": { | ||
"@apollo-elements/core": "^2.1.1", | ||
"@apollo-elements/mixins": "^5.0.1", | ||
"@apollo-elements/core": "^2.1.2", | ||
"@apollo-elements/mixins": "^5.0.3", | ||
"@microsoft/fast-element": "^1.6.2", | ||
@@ -72,0 +59,0 @@ "tslib": "^2.3.1" |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
364265
6764