I've been working on creating discord bots using discord.js, and they've gotten large enough that I'd like to be able to set up automated testing for them - I've found this library (corde), but as it doesn't seem to be widely used, I'd like to see if there are other, more mature options available out there first.
Any help would be greatly appreciated. Manually testing bot commands one at a time is growing somewhat tiring.
If you read some of the examples in the github repo, you can simply set the prefix of all of your bots as the same (or change the code below) and then as the client logs in, it tests a command.
const { group, test, command, beforeStart, afterAll } = require("corde");
const { client, loginBot } = require("..");
beforeStart(() => {
loginBot();
});
group("main commands", () => {
test("Hello command should return... hello!!", () => {
expect("ping").shouldReturn("Ping?");
});
});
afterAll(() => {
client.destroy();
});
There is far more code that will help in the repo, here is the main index.js file if you need more assistance, or you could ask in a comment below.
Related
Would anyone have any clue what is going on here:
I am trying to create a websocket connection for my company, via API GateWay on AWS. when I use wscat in terminal to connect to my socket it all works fine. It does however, say there was an internal error, but it would still works when I call actions
I have this code in my react code base:
useEffect(() => {
socket.current = new WebSocket(url);
socket.current.onopen = () => {
console.log("ws opened");
socket.current.send(
JSON.stringify({
action: "handleUpdateUserEmail",
email: "test#123.com",
})
);
};
socket.current.onclose = () => console.log("ws closed");
return () => {
socket.current.close();
};
}, []);
I have my dynamoDB database setup to initiate a record in a table to store the current session id, however, I am getting a blank record + another record with the email updates like this code is supposed to do. But it is not closing out old sessions, if I refresh my browser a few times it doesn't close the connections and delete them from the database. Using Wscat it works as intended tho. This is really throwing me in a loop, and I can barely find much online about. The things I am finding online so to do this. Idk what im missing here. I would really appreciate some help
Background
I have recently upgraded a fairly sizeable React app to React 18 and for the most part it has been great. One of the key changes is the new double mount in development causing useEffect hooks to all run twice, this is clearly documented in their docs.
I have read their new effect documentation https://beta.reactjs.org/learn/lifecycle-of-reactive-effects and although it is quite detailed there is a use case I believe I have found which is not very well covered.
The issue
Essentially the issue I have run into is I am implementing OAuth integration with a third-party product. The flow:
-> User clicks create integration -> Redirect to product login -> Gets redirected back to our app with authorisation code -> We hit our API to finalise the integration (HTTP POST request)
The problem comes now that the useEffect hook runs twice it means that we would hit this last POST request twice, first one would succeed and the second would fail because the integration is already setup.
This is not potentially a major issue but the user would see an error message even though the request worked and just feels like a bad pattern.
Considered solutions
Refactoring to use a button
I could potentially get the user to click a button on the redirect URL after they have logged into the third-party product. This would work and seems to be what the React guides recommend (Although different use case they suggested - https://beta.reactjs.org/learn/you-might-not-need-an-effect#sharing-logic-between-event-handlers).
The problem with this is that the user has already clicked a button to create the integration so it feels like a worse user experience.
Ignore the duplicate API call
This issue is only a problem in development however it is still a bit annoying and feels like an issue I want to explore further
Code setup
I have simplified the code for this example but hopefully this gives a rough idea of how the intended code is meant to function.
const IntegrationRedirect: React.FC = () => {
const navigate = useNavigate();
const organisationIntegrationsService = useOrganisationIntegrationsService();
// Make call on the mount of this component
useEffect(() => {
// Call the method
handleCreateIntegration();
}, []);
const handleCreateIntegration = async (): Promise<void> => {
// Setup request
const request: ICreateIntegration = {
authorisationCode: ''
};
try {
// Make service call
const setupIntegrationResponse = await organisationIntegrationsService.createIntegration(request);
// Handle error
if (setupIntegrationResponse.data.errors) {
throw 'Failed to setup integrations';
}
// Navigate away on success
routes.organisation.integrations.navigate(navigate);
}
catch (error) {
// Handle error
}
};
return ();
};
What I am after
I am after suggestions based on the React 18 changes that would handle this situation, I feel that although this is a little specific/niche it is still a viable use case. It would be good to have a clean way to handle this as OAuth integration is quite a common flow for integration between products.
You can use the useRef() together with useEffect() for a workaround
const effectRan = useRef(false)
useEffect(() => {
if (effectRan.current === false) {
// do the async data fetch here
handleCreateIntegration();
}
//cleanup function
return () => {
effectRan.current = true // this will be set to true on the initial unmount
}
}, []);
This is a workaround suggested by Dave Gray on his youtube channel https://www.youtube.com/watch?v=81faZzp18NM
I have a test-suite containing 37 tests that are testing one of my views. Locally, all tests pass without any issues, but when I push my code, the test-suite fails in our pipeline (we are using GitLab).
The error-output from the logs in CI are extremely long (thousands of lines, it even exceeds the limit set by GitLab). The error consists of many "not wrapped in act()"-, and "nested calls to act() are not supported"-warnings (Moslty triggered by useTranslation() from I18Next and componens like Tooltip from Material-UI).
My guess is that async-data from the API (mocked using msw) triggers a state-update after a call to act() has completed, but I'm not sure how to prove this, or even figure out what tests are actually failing.
Has anyone experienced something similar, or knows what's up?
Example of a failing test:
it.each([
[Status.DRAFT, [PAGE_1, PAGE_11, PAGE_2, PAGE_22, PAGE_3]],
[Status.PUBLISHED, [PAGE_1, PAGE_12, PAGE_2, PAGE_21, PAGE_22, PAGE_221]],
])('should be possible to filter nodes by status %s', async (status, expectedVisiblePages) => {
renderComponent();
await waitFor(() => {
expect(screen.queryByRole('progressbar')).not.toBeInTheDocument();
});
userEvent.click(screen.getByLabelText('components.FilterMenu.MenuLabel'));
const overlay = await screen.findByRole('presentation');
await waitFor(() => expect(within(overlay).queryByRole('progressbar')).not.toBeInTheDocument());
userEvent.click(within(overlay).getByText(`SiteStatus.${status}`));
userEvent.keyboard('{Esc}');
const items = await screen.findAllByRole('link');
expect(items).toHaveLength(expectedVisiblePages.length);
expectedVisiblePages.forEach((page) => expect(screen.getByText(page.title)).toBeInTheDocument());
});
Update 1
Okay. So I've narrowed it down to this line:
const items = await screen.findAllByRole('link');
There seems to be a lot of stuff happening while waiting for things to appear. I believed that the call to findAllByRole was already wrapped in act() and that this would make sure all updates has been applied.
Update 2
It seems to be a problem partly caused by tests timing out.
I believe multiple calls to waitFor(...) and find[All]By(...) in the same test, in addition to a slow runner, collectively exceeds the timout for the test (5000ms by default). I've tried to adjust this limit by running the tests with --testTimeout 60000. And now, some of the tests are passing. I'm still struggling with the "act()"-warnings. Theese might be caused by a different problem entirely...
The bughunt continues...
After many attempts, I finally found the answer. The CI-server only has 2 CPUs available, and by running the tests with --maxWorkers=2 --maxConcurrent=2, instead of the default --maxWorkers=100% --maxConcurrent=5, proved to solve the problem.
This is a common issue ;)
I guess, you see this problem on CI Server because of the environment (less cpu/mem/etc).
This warning is because you do some async action but did not finish for complete it (because it's async).
You can read more about this issue in this article: https://kentcdodds.com/blog/fix-the-not-wrapped-in-act-warning
The best solution is waiting for the operation to finish. For example by adding loading indicator and waiting for element remove.
For example:
it('should show empty table', async () => {
const [render] = createRenderAndStore()
mockResponse([])
const { container } = render(<CrmClientsView />) // - this view do async request in first render
await waitForElementToBeRemoved(screen.queryByRole('test-loading'))
await waitFor(() => expect(container).toHaveTextContent('There is no data'))
})
I been trying to get mailchimp with my react project but for the love of me just can't. I don't know why I can't get the ping and despite having the node module installed, it tells me it isnt.
im using these docs - https://mailchimp.com/developer/marketing/guides/quick-start/
and this code with ofcourse my information. Any clues, am I missing a key step here? has anyone got experience with this and if so, can i see your code for it ?
const mailchimp = require("#mailchimp/mailchimp_marketing");
mailchimp.setConfig({
apiKey: "YOUR_API_KEY",
server: "YOUR_SERVER_PREFIX",
});
async function run() {
const response = await mailchimp.ping.get();
console.log(response);
}
run();
I am working on a real-time multiplayer board game built using node and socket.io for the backend and react + redux for the frontend. It's the first time I'm doing a project of this sort, i.e. real-time and multiplayer.
I am unsure on how best to go about integration/system testing. How can I actually automate spinning up, say 10 frontends and having them play a game together? Should I use a testing framework for this and if so, which one would be a good choice and why?
I found this question with the same question. I have figured out a way for it to work, which I'm guessing you have as well by now, but for someone else to come across:
A clarification on terms: integration testing can be done for react with things like Jest + enzyme, using mount(). I'm answering this based on looking for end-to-end / acceptance testing, where you're essentially testing your product from the user's standpoint (here, navigating around on a website).
As this is from the user's perspective, I believe it is irrelevant that you're using React.
So, how to do this? There are many JS testing options. That resource can help understand which testing package you might want to select. You want something that simulates an actual browser.
In investigating some of the options listed in the above resource, I have found that:
TestCafe does not support multi-page testing.
WebdriverIO does support multiple browsers at the same time.
Puppeteer does support multiple pages at the same time.
edit: I initially proposed using nightmare. However, I was getting some wonky behavior when running multiple tests (unexpected timeouts, Electron instances not closing properly), and have investigated some other options. But I'll retain the information for reference:
I selected nightmare because it was advertised as simple.
Below is an example test, using Jest and nightmare (and some sloppy TypeScript). The site has a button to end the player's turn, and there is a header that indicates whose turn it is. I'll simulate clicking that button and making sure the header changes as expected. Also note that you'll need your dev server and frontend running during these tests.
import * as Nightmare from 'nightmare';
let nightmare1: Nightmare;
let nightmare2: Nightmare;
beforeEach(async () => {
nightmare1 = new Nightmare({ show: true })
nightmare2 = new Nightmare({ show: true })
await nightmare1
.goto('http://127.0.0.1:3000');
await nightmare2
.goto('http://127.0.0.1:3000');
});
afterEach(async () => {
await nightmare1.end();
await nightmare2.end();
});
it('sockets turn changes via End Turn button', async () => {
expect.assertions(6);
// Both display the same player's turn ("Red's Turn")
const startingTurnIndicator1 = await nightmare1
.evaluate(() => document.querySelector('h1').innerText);
const startingTurnIndicator2 = await nightmare2
.evaluate(() => document.querySelector('h1').innerText);
expect(startingTurnIndicator1).toBe(startingTurnIndicator2);
// Both change ("Blue's Turn")
const oneClickTI1 = await nightmare1
.click('button')
.evaluate(() => document.querySelector('h1').innerText)
const oneClickTI2 = await nightmare2
.evaluate(() => document.querySelector('h1').innerText);
expect(oneClickTI1).toBe(oneClickTI2);
expect(oneClickTI1).not.toBe(startingTurnIndicator1);
// Both change back ("Red's Turn")
const twoClickTI2 = await nightmare2
.click('button')
.evaluate(() => document.querySelector('h1').innerText)
const twoClickTI1 = await nightmare1
.evaluate(() => document.querySelector('h1').innerText);
expect(twoClickTI1).toBe(twoClickTI2);
expect(twoClickTI1).toBe(startingTurnIndicator2);
expect(twoClickTI1).not.toBe(oneClickTI1);
});
I'm not sure how good the actual code in this test is, but it works.