playwright-testing-library
Version:
playwright + dom-testing-library
124 lines • 6.52 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.synchronousQueryNames = exports.screenFor = exports.queriesFor = exports.isNotFindQuery = exports.isAllQuery = exports.allQueryNames = exports.LocatorPromise = void 0;
const test_1 = require("@playwright/test");
const dom_1 = require("@testing-library/dom");
const helpers_1 = require("../helpers");
const helpers_2 = require("./helpers");
const isAllQuery = (query) => query.includes('All');
exports.isAllQuery = isAllQuery;
const isFindQuery = (query) => query.startsWith('find');
const isNotFindQuery = (query) => !query.startsWith('find');
exports.isNotFindQuery = isNotFindQuery;
const allQueryNames = Object.keys(dom_1.queries);
exports.allQueryNames = allQueryNames;
const synchronousQueryNames = allQueryNames.filter(isNotFindQuery);
exports.synchronousQueryNames = synchronousQueryNames;
const findQueryToGetQuery = (query) => query.replace(/^find/, 'get');
const findQueryToQueryQuery = (query) => query.replace(/^find/, 'query');
class LocatorPromise extends Promise {
constructor(executor, config) {
super(executor);
this.config = config;
}
/**
* Wrap an `async` function `Promise` return value in a `LocatorPromise`.
* This allows us to use `async/await` and still return a custom
* `LocatorPromise` instance instead of `Promise`.
*
* @param fn
* @returns
*/
static wrap(fn, config) {
return (...args) => LocatorPromise.from(fn(...args), config);
}
static from(promise, config) {
return new LocatorPromise((resolve, reject) => {
promise.then(resolve).catch(reject);
}, config);
}
within() {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
return queriesFor(this, this.config);
}
}
exports.LocatorPromise = LocatorPromise;
const locatorFor = (root, query, options) => root.locator(`${(0, helpers_2.queryToSelector)(query)}=${JSON.stringify(options, helpers_1.replacer)}`);
const augmentedLocatorFor = (root, query, options, config) => {
const locator = locatorFor(root, query, options);
return new Proxy(locator, {
get(target, property, receiver) {
return property === 'within'
? // eslint-disable-next-line @typescript-eslint/no-use-before-define
() => queriesFor(target, config)
: Reflect.get(target, property, receiver);
},
});
};
const createFindQuery = (root, query, { asyncUtilTimeout, asyncUtilExpectedState } = {}) => LocatorPromise.wrap((...[id, options, waitForElementOptions]) => __awaiter(void 0, void 0, void 0, function* () {
const settledRoot = root instanceof LocatorPromise ? yield root : root;
const synchronousOptions = (options ? [id, options] : [id]);
const locator = locatorFor(settledRoot, findQueryToQueryQuery(query), synchronousOptions);
const { state: expectedState = asyncUtilExpectedState, timeout = asyncUtilTimeout } = waitForElementOptions !== null && waitForElementOptions !== void 0 ? waitForElementOptions : {};
try {
yield locator.first().waitFor({ state: expectedState, timeout });
}
catch (error) {
// In the case of a `waitFor` timeout from Playwright, we want to
// surface the appropriate error from Testing Library, so run the
// query one more time as `get*` knowing that it will fail with the
// error that we want the user to see instead of the `TimeoutError`
if (error instanceof test_1.errors.TimeoutError) {
const timeoutLocator = locatorFor(settledRoot, findQueryToGetQuery(query), synchronousOptions).first();
// Handle case where element is attached, but hidden, and the expected
// state is set to `visible`. In this case, dereferencing the
// `Locator` instance won't throw a `get*` query error, so just
// surface the original Playwright timeout error
if (expectedState === 'visible' && !(yield timeoutLocator.isVisible())) {
throw error;
}
// In all other cases, dereferencing the `Locator` instance here should
// cause the above `get*` query to throw an error in Testing Library
yield timeoutLocator.waitFor({ state: expectedState, timeout });
}
}
return locator;
}), { asyncUtilExpectedState, asyncUtilTimeout });
/**
* Given a `Page` or `Locator` instance, return an object of Testing Library
* query methods that return a `Locator` instance for the queried element
*
* @internal this API is not currently intended for public usage and may be
* removed or changed outside of semantic release versioning. If possible, you
* should use the `locatorFixtures` with **@playwright/test** instead.
* @see {@link locatorFixtures}
*
* @param root `Page` or `Locator` instance to use as the query root
* @param config Testing Library configuration to apply to queries
*
* @returns object containing scoped Testing Library query methods
*/
const queriesFor = (root, config) => allQueryNames.reduce((rest, query) => (Object.assign(Object.assign({}, rest), { [query]: isFindQuery(query)
? createFindQuery(root, query, config)
: (...options) => root instanceof LocatorPromise
? root.then(r => locatorFor(r, query, options))
: augmentedLocatorFor(root, query, options, config) })), {});
exports.queriesFor = queriesFor;
const screenFor = (page, config) => Proxy.revocable(page, {
get(target, property, receiver) {
return (0, helpers_2.includes)(allQueryNames, property)
? queriesFor(page, config)[property]
: Reflect.get(target, property, receiver);
},
});
exports.screenFor = screenFor;
//# sourceMappingURL=queries.js.map