UNPKG

@apollo/client

Version:

A fully-featured caching GraphQL client.

181 lines 9.13 kB
import { __assign, __extends } from "tslib"; import { invariant } from "../../../utilities/globals/index.js"; import { equal } from "@wry/equality"; import { ApolloLink } from "../../../link/core/index.js"; import { Observable, addTypenameToDocument, removeClientSetsFromDocument, cloneDeep, stringifyForDisplay, print, getOperationDefinition, getDefaultValues, removeDirectivesFromDocument, checkDocument, } from "../../../utilities/index.js"; function requestToKey(request, addTypename) { var queryString = request.query && print(addTypename ? addTypenameToDocument(request.query) : request.query); var requestKey = { query: queryString }; return JSON.stringify(requestKey); } var MockLink = /** @class */ (function (_super) { __extends(MockLink, _super); function MockLink(mockedResponses, addTypename, options) { if (addTypename === void 0) { addTypename = true; } if (options === void 0) { options = Object.create(null); } var _a; var _this = _super.call(this) || this; _this.addTypename = true; _this.showWarnings = true; _this.mockedResponsesByKey = {}; _this.addTypename = addTypename; _this.showWarnings = (_a = options.showWarnings) !== null && _a !== void 0 ? _a : true; if (mockedResponses) { mockedResponses.forEach(function (mockedResponse) { _this.addMockedResponse(mockedResponse); }); } return _this; } MockLink.prototype.addMockedResponse = function (mockedResponse) { var normalizedMockedResponse = this.normalizeMockedResponse(mockedResponse); var key = requestToKey(normalizedMockedResponse.request, this.addTypename); var mockedResponses = this.mockedResponsesByKey[key]; if (!mockedResponses) { mockedResponses = []; this.mockedResponsesByKey[key] = mockedResponses; } mockedResponses.push(normalizedMockedResponse); }; MockLink.prototype.request = function (operation) { var _this = this; var _a; this.operation = operation; var key = requestToKey(operation, this.addTypename); var unmatchedVars = []; var requestVariables = operation.variables || {}; var mockedResponses = this.mockedResponsesByKey[key]; var responseIndex = mockedResponses ? mockedResponses.findIndex(function (res, index) { var mockedResponseVars = res.request.variables || {}; if (equal(requestVariables, mockedResponseVars)) { return true; } if (res.variableMatcher && res.variableMatcher(operation.variables)) { return true; } unmatchedVars.push(mockedResponseVars); return false; }) : -1; var response = responseIndex >= 0 ? mockedResponses[responseIndex] : void 0; // There have been platform- and engine-dependent differences with // setInterval(fn, Infinity), so we pass 0 instead (but detect // Infinity where we call observer.error or observer.next to pend // indefinitely in those cases.) var delay = (response === null || response === void 0 ? void 0 : response.delay) === Infinity ? 0 : (_a = response === null || response === void 0 ? void 0 : response.delay) !== null && _a !== void 0 ? _a : 0; var configError; if (!response) { configError = new Error("No more mocked responses for the query: ".concat(print(operation.query), "\nExpected variables: ").concat(stringifyForDisplay(operation.variables), "\n").concat(unmatchedVars.length > 0 ? "\nFailed to match ".concat(unmatchedVars.length, " mock").concat(unmatchedVars.length === 1 ? "" : "s", " for this query. The mocked response had the following variables:\n").concat(unmatchedVars.map(function (d) { return " ".concat(stringifyForDisplay(d)); }).join("\n"), "\n") : "")); if (this.showWarnings) { console.warn(configError.message + "\nThis typically indicates a configuration error in your mocks " + "setup, usually due to a typo or mismatched variable."); } } else { if (response.maxUsageCount && response.maxUsageCount > 1) { response.maxUsageCount--; } else { mockedResponses.splice(responseIndex, 1); } var newData = response.newData; if (newData) { response.result = newData(operation.variables); mockedResponses.push(response); } if (!response.result && !response.error && response.delay !== Infinity) { configError = new Error("Mocked response should contain either `result`, `error` or a `delay` of `Infinity`: ".concat(key)); } } return new Observable(function (observer) { var timer = setTimeout(function () { if (configError) { try { // The onError function can return false to indicate that // configError need not be passed to observer.error. For // example, the default implementation of onError calls // observer.error(configError) and then returns false to // prevent this extra (harmless) observer.error call. if (_this.onError(configError, observer) !== false) { throw configError; } } catch (error) { observer.error(error); } } else if (response && response.delay !== Infinity) { if (response.error) { observer.error(response.error); } else { if (response.result) { observer.next(typeof response.result === "function" ? response.result(operation.variables) : response.result); } observer.complete(); } } }, delay); return function () { clearTimeout(timer); }; }); }; MockLink.prototype.normalizeMockedResponse = function (mockedResponse) { var _a; var newMockedResponse = cloneDeep(mockedResponse); var queryWithoutClientOnlyDirectives = removeDirectivesFromDocument([{ name: "connection" }, { name: "nonreactive" }], checkDocument(newMockedResponse.request.query)); invariant(queryWithoutClientOnlyDirectives, 67); newMockedResponse.request.query = queryWithoutClientOnlyDirectives; var query = removeClientSetsFromDocument(newMockedResponse.request.query); if (query) { newMockedResponse.request.query = query; } mockedResponse.maxUsageCount = (_a = mockedResponse.maxUsageCount) !== null && _a !== void 0 ? _a : 1; invariant(mockedResponse.maxUsageCount > 0, 68, mockedResponse.maxUsageCount); this.normalizeVariableMatching(newMockedResponse); return newMockedResponse; }; MockLink.prototype.normalizeVariableMatching = function (mockedResponse) { var request = mockedResponse.request; if (mockedResponse.variableMatcher && request.variables) { throw new Error("Mocked response should contain either variableMatcher or request.variables"); } if (!mockedResponse.variableMatcher) { request.variables = __assign(__assign({}, getDefaultValues(getOperationDefinition(request.query))), request.variables); mockedResponse.variableMatcher = function (vars) { var requestVariables = vars || {}; var mockedResponseVariables = request.variables || {}; return equal(requestVariables, mockedResponseVariables); }; } }; return MockLink; }(ApolloLink)); export { MockLink }; // Pass in multiple mocked responses, so that you can test flows that end up // making multiple queries to the server. // NOTE: The last arg can optionally be an `addTypename` arg. export function mockSingleLink() { var mockedResponses = []; for (var _i = 0; _i < arguments.length; _i++) { mockedResponses[_i] = arguments[_i]; } // To pull off the potential typename. If this isn't a boolean, we'll just // set it true later. var maybeTypename = mockedResponses[mockedResponses.length - 1]; var mocks = mockedResponses.slice(0, mockedResponses.length - 1); if (typeof maybeTypename !== "boolean") { mocks = mockedResponses; maybeTypename = true; } return new MockLink(mocks, maybeTypename); } //# sourceMappingURL=mockLink.js.map