-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Command/Context API to Let External Concerns Manipulate Counterfact #730
Comments
Theoretically, this can be done today. import { counterfact } from "counterfact/dist/server/app.js";
const {
contextRegistry,
koaApp,
koaMiddleware: middleware,
registry,
start,
} = await counterfact({ /* config values */ }); We need to add an exports property to package.json so the import will look like this: import { counterfact } from "counterfact"; And we need to document the API. |
We also need to break out the REPL server so it doesn't automatically start when we call |
Here's a simplified version of what that might look like in a unit test. import { counterfact } from "counterfact";
import { chromium } from 'playwright';
let page; // API for controlling Playwright
let rootContext; // API for controlling Counterfact
function attemptToLogIn(username = "admin", password="1Secret!") {
await page.goto('https://example.com/login');
await page.fill('#username', username);
await page.fill('#password', password);
await page.click('#loginButton');
await page.waitForNavigation();
await page.content();
}
beforeAll(, async() => {
const browser = await chromium.launch({ headless: true });
const playwrightContext = await browser.newContext();
page = await playwrightContext.newPage();
{ rootContext } = await counterfact({port: 8100, openApi: './path/to/api.yaml'});
});
it("handles incorrect password", async () => {
rootContext.passwordResponse = "incorrect";
await page = attemptToLogIn();
expect page.isVisible('#authentication-error').toBe(true);
});
it("loads the dashboard when successful", async () => {
rootContext.passwordResponse = "ok";
await attemptToLogIn();
expect page.isVisible('#dashboard').toBe(true)
});
it("prompts for password change", async () => {
rootContext.passwordResponse = "expired";
await attemptToLogIn();
expect page.isVisible('#password-change-form').toBe(true);
}); This assumes there's logic in export function POST ($) {
if ($.context.passwordResponse == "ok") return $.response[200];
if ($.context.passwordResponse = "expired") return $.response[403].header("reason", "expired-password");
return $.response[401];
} If that feels too hand-wavy, you could build out a minimal implementation of storing and validating credentials. It's a question of how much you want to approximate real business logic in mock APIs. it("prompts for password change", async () => {
rootContext.addUser({ username: "bob", password: "test", expired: true});
await attemptToLogIn("bob", "test");
expect page.isVisible('#password-change-form').toBe(true);
}); |
Presently we can use the REPL to work with a specific context and toggle various settings, alter data, etc, while running our UI against the mock server so we can test various alternating scenarios. Think of an authentication endpoint that might have 3 or 4 different response types (invalid password, password change required, etc).
Ideally we could have a set of API calls to the Counterfact server that have nothing to do with the Open API spec, but are specific to controlling Counterfact. In a Playwright test I could have a UI test that exercises all the various paths of an auth scenario (see above) without having to "bake" into the mock logic special hardcoded values such as different usernames that exercise the various response paths. Instead we could just have our mock context expose functions that let us easily toggle back and forth between the various response states. Our E2E test could run a set of test, then hit the Counterfact command API to switch the response state, rerun the tests and have it exercise the other paths.
The text was updated successfully, but these errors were encountered: