Testing conditional rendering in child component

Hi, I am trying to test a particular interaction in my component. I have two components, let's call them Parent and Toast. Toast is a child of the Parent component. Below is a code snippet from the Toast component:
imports...

interface Props {}
export const [toastVisibility, setToastVisibility] = createSignal(false);

const handleCloseToast = () => {
setToastVisibility(false);
};

const Toast: Component<Props> = (props) => {
const derivedSignal = () => {
if (toastVisibility()) {
// Test is able to reach this line
console.log("SHOULD BE SHOWING TOAST NOW..............");
console.log("toastVisibility: ", toastVisibility());
// After button click, the signal is True
return toastVisibility();
}
console.log("toastType: ", toastType);
return toastVisibility();
};
return (
<Show when={derivedSignal()} fallback={<>not showing toast</>}>
TOAST SHOWING
</Show>
);
};

export default Toast;
imports...

interface Props {}
export const [toastVisibility, setToastVisibility] = createSignal(false);

const handleCloseToast = () => {
setToastVisibility(false);
};

const Toast: Component<Props> = (props) => {
const derivedSignal = () => {
if (toastVisibility()) {
// Test is able to reach this line
console.log("SHOULD BE SHOWING TOAST NOW..............");
console.log("toastVisibility: ", toastVisibility());
// After button click, the signal is True
return toastVisibility();
}
console.log("toastType: ", toastType);
return toastVisibility();
};
return (
<Show when={derivedSignal()} fallback={<>not showing toast</>}>
TOAST SHOWING
</Show>
);
};

export default Toast;
The Parent component has a button that fires an API call. If there is an error in sending the API call, the signal that controls the visibility of the Toast component is set to True
try {
const res = await fireApiCall("/dummy/api") // This method throws an error if status code is not 200
...
}
catch (error: unknown) {
if (error instanceof Error) {
// Code reaches this line
console.log("SETTING TOAST VISIBILITY TO TRUE");
setToastVisibility(true);
} else {
throw error;
}
}
try {
const res = await fireApiCall("/dummy/api") // This method throws an error if status code is not 200
...
}
catch (error: unknown) {
if (error instanceof Error) {
// Code reaches this line
console.log("SETTING TOAST VISIBILITY TO TRUE");
setToastVisibility(true);
} else {
throw error;
}
}
The problem Im facing is that the code inside the <Show> does not seem to re-render and Im not sure why. I also console.log the value of toastVisibility and I can confirm that its initially set to false and after clicking the button, its set to true
7 Replies
TicTacMan
TicTacMan8mo ago
This is my test:
it("if saving is not successful, the user should be notified", async () => {
mocks.fireApiCall.mockImplementation(
(
division: string,
dataEndpoint: string,
action: BcAction,
entityId?: string,
getProperties?: string[],
body?: Record<string, any>
) => {
console.log("dataendpoint: " + dataEndpoint);

if (dataEndpoint === "/dummy/api") {
console.log("throwing error now");
throw new Error("Error!");
}
console.log("Not throwing error");
return data;
}
);

const { container, unmount } = await renderComponent({});

const saveButton = screen.getByRole("button", {
name: /save/i,
});

// User event
await userEvent.click(saveButton);

// Assert
expect(screen.queryByText("not showing toast")).not.toBeInTheDocument();
});
it("if saving is not successful, the user should be notified", async () => {
mocks.fireApiCall.mockImplementation(
(
division: string,
dataEndpoint: string,
action: BcAction,
entityId?: string,
getProperties?: string[],
body?: Record<string, any>
) => {
console.log("dataendpoint: " + dataEndpoint);

if (dataEndpoint === "/dummy/api") {
console.log("throwing error now");
throw new Error("Error!");
}
console.log("Not throwing error");
return data;
}
);

const { container, unmount } = await renderComponent({});

const saveButton = screen.getByRole("button", {
name: /save/i,
});

// User event
await userEvent.click(saveButton);

// Assert
expect(screen.queryByText("not showing toast")).not.toBeInTheDocument();
});
TicTacMan
TicTacMan8mo ago
Once the button is clicked, I expect the fallback of the <Show>, i.e "not showing toast" to not be in the document. But after inspecting the DOM after the user clicks, I see that its still in the DOM Whats strange is that I can see these console.logs running after the click event, which implies that the reactivity is already triggering the re-evaluation of derivedSignal()
No description
Alex Lohr
Alex Lohr8mo ago
Try await find instead of query
TicTacMan
TicTacMan8mo ago
Replaced the expect with this:
expect(await screen.findByText(/"TOAST SHOWING"/i)).toBeInTheDocument();
expect(await screen.findByText(/"TOAST SHOWING"/i)).toBeInTheDocument();
Still fails...
Alex Lohr
Alex Lohr8mo ago
I'm currently abroad, and will need to wait until I get to my desk before I can test this myself.
TicTacMan
TicTacMan8mo ago
No worries, do you know if there is some kind of playground environment where I can try to mimic this setup for you?
Alex Lohr
Alex Lohr8mo ago
If you have a minimal reconstruction in a single test file, that would help