Conversation
This stack of pull requests is managed by Graphite. Learn more about stacking. |
3d22f8d to
1f8f47e
Compare
1f8f47e to
562a606
Compare
bdf2921 to
2388be3
Compare
2388be3 to
4961fee
Compare
| @@ -0,0 +1,363 @@ | |||
| # 🧪 @shopify/ui-extensions-tester | |||
There was a problem hiding this comment.
nit: naming. Random thoughts without much merit:
ui-extensions-testing-library- similar to React Testing Libraryui-extensions-test- shorter for no good reason
f1f74ae to
a265b94
Compare
|
/snapit |
088e832 to
4b27af2
Compare
vividviolet
left a comment
There was a problem hiding this comment.
This is amazing! I have a few questions/suggestions
vividviolet
left a comment
There was a problem hiding this comment.
Looks great! Thanks for addressing all the feedback. This is good to merge - I just have a few questions that could be addressed if needed in follow up prs
| if (tomlVersion !== API_VERSION) { | ||
| throw new Error( | ||
| `api_version "${tomlVersion ?? '(not found)'}" does not match ` + | ||
| `the version supported by @shopify/ui-extensions-tester ("${API_VERSION}"). ` + |
There was a problem hiding this comment.
This means we'd have to do do a new version of the test library for every library release even though most of the code remains the same. I do see the value in making it simple for developers though. We might want to automate this somehow
There was a problem hiding this comment.
Yes, we'd need to release ui-extensions-tester alongside ui-extensions but if no changes are needed then the version bump would happen automatically. It gets set in a build step.
|
|
||
| /** | ||
| * Creates a mock `SubscribableSignalLike` that wraps a static value. | ||
| * The `subscribe` callback is never invoked since test values are static. |
There was a problem hiding this comment.
How do we write tests to work with changing signals then?
There was a problem hiding this comment.
Since preact is the default, I think most extensions could be tested in a functional style. In other words, the mock shopify object won't have working signals but I don't think that matters.
To illustrate:
Let's say your extension has a button to change cart quantities and it also subscribes to line items. You wouldn't need the subscription to be fully functional. You could just test it in two steps:
// test that the button works
const mock = vi.fn().mockResolvedValue(
createResult('applyCartLineChange');
);
extension.shopify.applyCartLineChange = mock;
await extension.render();
const button = document.body.querySelector('s-button');
fireEvent('click', button);
// Make sure the button changes the quantity
await waitFor(() => {
expect(mock).toHaveBeenCalledWith(...);
});...
// test that the extension renders the lines
const line = createLineItem();
// This essentially simulates a subscription update:
extension.shopify.lines = [line];
await extension.render();
const text = document.body.querySelector('s-text');
// Make sure the line's quantity was rendered:
expect(text.textContent).toContain(line.quantity);This testing style assumes the shopify API fully works as specified -- I think that assumption is fine.
There was a problem hiding this comment.
Thanks for calling this out, Trish. I documented the suggested pattern to use for this.
|
|
||
| /** | ||
| * Creates an isolated temp directory for a single test file. | ||
| * Each test file gets its own directory so tests can run in parallel |
There was a problem hiding this comment.
Can you clarify why we need to do this? Tests shouldn't mutate the toml so why do we need to copy these tests to their own directory and clone the toml?
There was a problem hiding this comment.
This is just for the internal ui-extensions-tester test suite. Developers would never use this.
It's necessary because some of the tests need to work with different TOML files to simulate different configurations. The fixtures getting copied here are just for defining an extension that can be imported and executed. The fixtures don't include a TOML file.
The first approach I tried was to write a local TOML file before each test but I started seeing flakiness. It worked better when creating a unique TOML file per test.
jamesvidler
left a comment
There was a problem hiding this comment.
I ran into a snag with the error ReferenceError: __filename is not defined when running the tests, so I had to add the following to my vitetest.config
export default defineConfig({
esbuild: {
jsx: "automatic",
jsxImportSource: "preact",
},
test: {
environment: "jsdom",
//NEEDED TO ADD THIS, or a I got an error ReferenceError: __filename is not defined when running the tests
server: {
deps: {
inline: ["@shopify/ui-extensions-tester"],
},
},
},
});
It looks like we've patched that now, but I wasn't able to get the updated tgz package to relfect the changes.
I'm comfortable approving and we can test again once the package is publicly released and fix forward if neccessary or update the docs.

This adds a new
ui-extensions-testerlibrary, built during Hack Days (internal Shopify link).All stacks
ui-extensions-testerpackage setup <-- you are here👁️ How to review this PR
Example
Here's what it looks like so far in something like
your-app/extensions/your-ui-extension/tests/Extension.test.ts:More complete example:
checkout-basic-testing-example/tests/Checkout.test.tsRun it like this after checking out the branch for this PR:
🎩
To try it in a standalone app, you have to install a pre-built package: shopify-ui-extensions-tester-v2026.4.0-rc.1.tgz. This is because
/snapitdoesn't work before there's at least one public release.Add it to a
package.jsonfile like: