-
Notifications
You must be signed in to change notification settings - Fork 5
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
Loss of variable values in long requests #17
Comments
You have a couple of issues in your code which might be causing the problem you're seeing:
.exec(() => {
request(server)
.ws("/ws") /*...*/
}) should be: .exec(async () => {
await request(server)
.ws("/ws") /*...*/
}) or, ~equivalently: .exec(() => {
return request(server)
.ws("/ws") /*...*/
})
With both of those fixes, your code would look like this: describe("cambiar posición", () => {
test("válido", async () => {
let jugadorId1 = "",
jugadorId2 = "",
idZonaBatalla = 0,
idMano = 0;
await request(server)
.ws("/ws")
.sendJson(unirseASala1)
.expectJson((response: UnirASalaResponse) => {
jugadorId1 = response.payload.jugadorId as string;
})
.exec(async () => {
await request(server)
.ws("/ws")
.sendJson(unirseASala2)
.expectJson((response: UnirASalaResponse) => {
jugadorId2 = response.payload.jugadorId as string;
})
.sendJson(iniciarJuego(jugadorId2))
.close()
.expectClosed();
})
.expectJson()
.expectJson()
.sendJson(
colocarCarta(jugadorId1, PosBatalla.ATAQUE, idZonaBatalla, idMano)
)
.expectJson()
.sendJson(terminarTurno(jugadorId1))
.expectJson()
.exec(async () => {
await request(server).ws("/ws")
.sendJson(terminarTurno(jugadorId2))
.close()
.expectClosed();
})
.sendJson(cambiarPosicion(jugadorId1, idZonaBatalla))
.expectJson({
event: WebsocketEventTitle.CAMBIAR_POSICION,
payload: {
jugadorId: jugadorId1,
idZonaBatalla
},
});
});
}); Probably also worth saying that this test looks like it's really 2 long-lived players, rather than a single long-lived websocket and some shorter activities. You might be able to achieve the same with something more like this (apologies - in English since I'd probably do a terrible job of translating it): describe("cambiar posición", () => {
test("válido", async () => {
let jugadorId1 = "",
jugadorId2 = "",
idZonaBatalla = 0,
idMano = 0;
const jugador1Actions = request(server)
.ws("/ws")
.sendJson(unirseASala1)
.expectJson((response: UnirASalaResponse) => {
jugadorId1 = response.payload.jugadorId as string;
})
.expectJson() // waits for jugador 2 to join
.expectJson()
.sendJson(
colocarCarta(jugadorId1, PosBatalla.ATAQUE, idZonaBatalla, idMano)
)
.expectJson()
.sendJson(terminarTurno(jugadorId1))
.expectJson()
// TODO: ideally would wait on some response from jugador 2 here
.sendJson(cambiarPosicion(jugadorId1, idZonaBatalla))
.expectJson({
event: WebsocketEventTitle.CAMBIAR_POSICION,
payload: {
jugadorId: jugadorId1,
idZonaBatalla
},
});
const jugador2Actions = request(server)
.ws("/ws")
.sendJson(unirseASala2)
.expectJson((response: UnirASalaResponse) => {
jugadorId2 = response.payload.jugadorId as string;
})
.sendJson(iniciarJuego(jugadorId2))
// TODO: ideally would wait on some response from jugador 1 here
.sendJson(terminarTurno(jugadorId2));
await Promise.all([
jugador1Actions,
jugador2Actions,
]);
});
}); That approach is more suited to turn-based activities where each participant can wait for responses before continuing, so unless you can fill in the TODOs, you're probably better off sticking with what you have, to avoid races. |
@davidje13 Thank you very much for such a detailed answer, but my problem with the variables continues. The variable is not storing the value of the first request so the second request fails. I have made a shorter test where it fails. I hope you can give me some insight on how to maintain the value of the variable between different messages sent. I must be having a scope problem that I wish I could solve. Thanks in advance. describe('primer jugador inicia el juego', () => {
test('válido', async () => {
const nombreJugador1 = 'César'
const nombreJugador2 = 'Krister'
let jugador1Id = ''
const player1actions = request(server)
.ws('/ws')
.sendJson(unirASala(nombreJugador1))
.expectJson((response: UnirASalaResponse) => { // response: jugador 1 se une a sala
jugador1Id = response.payload.jugadorId as string
console.log('🚀 ~ file: iniciar-juego.test.ts:29 ~ .expectJson ~ jugador1Id:', jugador1Id)
})
.expectJson() // response: jugador 2 se une a sala
.sendJson(iniciarJuego(jugador1Id))
.expectJson((response: IniciarJuegoResponse) => { // response: jugador 1 inició el juego
console.log('🚀 ~ file: iniciar-juego.test.ts:34 ~ .expectJson ~ response:', response)
console.log('// response: jugador 1 inició el juego')
expect(response.event).toBe(WebsocketEventTitle.INICIAR_JUEGO)
expect(response.payload.respuesta).toBe(ResultadoIniciarJuego.JUEGO_INICIADO)
expect(response.payload.jugador?.nombre).toBe(nombreJugador1)
expect(response.payload.jugador?.nBarrera).toBe(MAX_BARRERA_CARDS)
expect(response.payload.jugador?.mano.length).toBe(MAX_MANO_CARDS)
expect(response.payload.jugador?.enTurno).toBe(true)
expect(response.payload.jugador?.nDeck).toBe(MAX_DECK - MAX_BARRERA_CARDS - MAX_MANO_CARDS)
expect(response.payload.jugadorEnemigo?.nombre).toBe(nombreJugador2)
expect(response.payload.jugadorEnemigo?.nBarrera).toBe(MAX_BARRERA_CARDS)
expect(response.payload.jugadorEnemigo?.nMano).toBe(MAX_MANO_CARDS)
expect(response.payload.jugadorEnemigo?.enTurno).toBe(false)
expect(response.payload.jugadorEnemigo?.nDeck).toBe(MAX_DECK - MAX_BARRERA_CARDS - MAX_MANO_CARDS)
})
const player2actions = request(server)
.ws('/ws')
.expectJson() // response: jugador 1 se une a sala
.sendJson(unirASala(nombreJugador2))
.expectJson()// response: jugador 2 se une a sala
.expectJson((response: IniciarJuegoResponse) => { // response: jugador 1 inició el juego
expect(response.event).toBe(WebsocketEventTitle.INICIAR_JUEGO)
expect(response.payload.respuesta).toBe(ResultadoIniciarJuego.JUEGO_INICIADO)
expect(response.payload.jugador?.nombre).toBe(nombreJugador2)
expect(response.payload.jugador?.nBarrera).toBe(MAX_BARRERA_CARDS)
expect(response.payload.jugador?.nDeck).toBe(MAX_DECK - MAX_BARRERA_CARDS - MAX_MANO_CARDS)
expect(response.payload.jugador?.mano.length).toBe(MAX_MANO_CARDS)
expect(response.payload.jugador?.enTurno).toBe(false)
expect(response.payload.jugadorEnemigo?.nombre).toBe(nombreJugador1)
expect(response.payload.jugadorEnemigo?.nBarrera).toBe(MAX_BARRERA_CARDS)
expect(response.payload.jugadorEnemigo?.nDeck).toBe(MAX_DECK - MAX_BARRERA_CARDS - MAX_MANO_CARDS)
expect(response.payload.jugadorEnemigo?.nMano).toBe(MAX_MANO_CARDS)
expect(response.payload.jugadorEnemigo?.enTurno).toBe(true)
})
await Promise.all([
player1actions,
player2actions
])
})
}) Error
|
Hi, I can't offer much help on that beyond saying it looks like it might be revealing an actual issue in the implementation (or at least an unintuituve behaviour). From your log line, player 1 is receiving: {
respuesta: 'JUEGO INICIADO',
jugador: {
nombre: 'Krister',
nBarrera: 5,
nDeck: 42,
mano: [Array],
enTurno: false
},
jugadorEnemigo: {
nombre: 'César',
nBarrera: 5,
nDeck: 42,
nMano: 5,
enTurno: true
}
} Which clearly has both players, but appears to be switched around (player 1 registers as "César", but this response from the server has "César" as the enemy, and "Krister" as the player). This doesn't appear to be an issue in the test, so I can only assume the system being tested is mixing up the players somewhere. It might be that this is always how it behaves, or it could be that the test is revealing some kind of race condition due to the speed of the actions. |
It is true that the app is returning a non-intuitive behavior because the backend is not currently validating the structure of the sent message. Because of this it does not return an error message indicating that the player id is not being sent. As can be seen in file iniciar-juego.test.ts:29 the variable is being stored correctly; but in the line websocket-acciones.ts:150 the id is not arriving and I show them in the log. console.log
� ~ file: iniciar-juego.test.ts:29 ~ .expectJson ~ jugador1Id: 370fb8ab-7b89-4f3e-
9ea6-a1b01e582bb8
at src/tests/server/websocket-acciones/iniciar-juego.test.ts:29:21
at async Promise.all (index 0)
console.log
� ~ file: websocket-acciones.ts:150 ~ iniciarJuego ~ jugadorId:
at iniciarJuego (src/server/websocket-acciones.ts:150:11) Anyway, I'll see how I can fix it in due course. Many thanks for everything. |
ok. I'll mark this as closed, but feel free to re-open if you manage to narrow down your issue and still need help. |
I have reduced the problem by adding the validation of the structure of the messages sent to the server. Now it can be better understood that the value of the "jugadorId" is not being sent because it is temporarily saved in the join room response (unirASala). Still, when trying to use that id to start the game (iniciarJuego), the variable does not have that updated value. As I said before, everything points to a problem with the scope that does not allow me to maintain the variable's value between requests/responses. From now on I am looking for alternatives on how to store the value and pass it to the subsequent request. describe('primer jugador inicia el juego', () => {
test('válido', async () => {
const nombreJugador1 = 'César'
const nombreJugador2 = 'Krister'
let jugador1Id = ''
const player1actions = request(server)
.ws('/ws')
.sendJson(unirASala(nombreJugador1))
.expectJson((response: UnirASalaResponse) => { // response: jugador 1 se une a sala
jugador1Id = response.payload.jugadorId as string
console.log('🚀 ~ file: iniciar-juego.test.ts:29 ~ .expectJson ~ jugador1Id:', jugador1Id)
})
.expectJson() // response: jugador 2 se une a sala
.sendJson(iniciarJuego(jugador1Id))
.expectJson((response: IniciarJuegoResponse) => { // response: jugador 1 inició el juego
console.log('🚀 ~ file: iniciar-juego.test.ts:34 ~ .expectJson ~ response:', response)
// console.log('// response: jugador 1 inició el juego')
expect(response.event).toBe(WebsocketEventTitle.INICIAR_JUEGO)
expect(response.payload.respuesta).toBe(ResultadoIniciarJuego.JUEGO_INICIADO)
expect(response.payload.jugador?.nombre).toBe(nombreJugador1)
expect(response.payload.jugador?.nBarrera).toBe(MAX_BARRERA_CARDS)
expect(response.payload.jugador?.mano.length).toBe(MAX_MANO_CARDS)
expect(response.payload.jugador?.enTurno).toBe(true)
expect(response.payload.jugador?.nDeck).toBe(MAX_DECK - MAX_BARRERA_CARDS - MAX_MANO_CARDS)
expect(response.payload.jugadorEnemigo?.nombre).toBe(nombreJugador2)
expect(response.payload.jugadorEnemigo?.nBarrera).toBe(MAX_BARRERA_CARDS)
expect(response.payload.jugadorEnemigo?.nMano).toBe(MAX_MANO_CARDS)
expect(response.payload.jugadorEnemigo?.enTurno).toBe(false)
expect(response.payload.jugadorEnemigo?.nDeck).toBe(MAX_DECK - MAX_BARRERA_CARDS - MAX_MANO_CARDS)
})
const player2actions = request(server)
.ws('/ws')
.expectJson() // response: jugador 1 se une a sala
.sendJson(unirASala(nombreJugador2))
.expectJson()// response: jugador 2 se une a sala
.expectJson((response: IniciarJuegoResponse) => { // response: jugador 1 inició el juego
expect(response.event).toBe(WebsocketEventTitle.INICIAR_JUEGO)
expect(response.payload.respuesta).toBe(ResultadoIniciarJuego.JUEGO_INICIADO)
expect(response.payload.jugador?.nombre).toBe(nombreJugador2)
expect(response.payload.jugador?.nBarrera).toBe(MAX_BARRERA_CARDS)
expect(response.payload.jugador?.nDeck).toBe(MAX_DECK - MAX_BARRERA_CARDS - MAX_MANO_CARDS)
expect(response.payload.jugador?.mano.length).toBe(MAX_MANO_CARDS)
expect(response.payload.jugador?.enTurno).toBe(false)
expect(response.payload.jugadorEnemigo?.nombre).toBe(nombreJugador1)
expect(response.payload.jugadorEnemigo?.nBarrera).toBe(MAX_BARRERA_CARDS)
expect(response.payload.jugadorEnemigo?.nDeck).toBe(MAX_DECK - MAX_BARRERA_CARDS - MAX_MANO_CARDS)
expect(response.payload.jugadorEnemigo?.nMano).toBe(MAX_MANO_CARDS)
expect(response.payload.jugadorEnemigo?.enTurno).toBe(true)
})
await Promise.all([
player1actions,
player2actions
])
}) Error
I add a postman test that helps to see more clearly the cause of the problem |
I have managed to solve the problem by separating the requests into 2 Promise.all() One for joining the room and getting the ids and the other one for the following actions. describe('primer jugador inicia el juego', () => {
test('válido', async () => {
const nombreJugador1 = 'César'
const nombreJugador2 = 'Krister'
let jugador1Id = ''
const player1join = request(server)
.ws('/ws')
.sendJson(unirASala(nombreJugador1))
.expectJson((response: UnirASalaResponse) => { // response: jugador 1 se une a sala
jugador1Id = response.payload.jugadorId as string
console.log('🚀 ~ file: iniciar-juego.test.ts:29 ~ .expectJson ~ jugador1Id:', jugador1Id)
})
.expectJson() // response: jugador 2 se une a sala
const player2join = request(server)
.ws('/ws')
.expectJson() // response: jugador 1 se une a sala
.sendJson(unirASala(nombreJugador2))
.expectJson()// response: jugador 2 se une a sala
await Promise.all([
player1join,
player2join
])
const player1actions = request(server)
.ws('/ws')
.sendJson(iniciarJuego(jugador1Id))
.expectJson((response: IniciarJuegoResponse) => { // response: jugador 1 inició el juego
console.log('🚀 ~ file: iniciar-juego.test.ts:34 ~ .expectJson ~ response:', response)
// console.log('// response: jugador 1 inició el juego')
expect(response.event).toBe(WebsocketEventTitle.INICIAR_JUEGO)
expect(response.payload.respuesta).toBe(ResultadoIniciarJuego.JUEGO_INICIADO)
expect(response.payload.jugador?.nombre).toBe(nombreJugador1)
expect(response.payload.jugador?.nBarrera).toBe(MAX_BARRERA_CARDS)
expect(response.payload.jugador?.mano.length).toBe(MAX_MANO_CARDS)
expect(response.payload.jugador?.enTurno).toBe(true)
expect(response.payload.jugador?.nDeck).toBe(MAX_DECK - MAX_BARRERA_CARDS - MAX_MANO_CARDS)
expect(response.payload.jugadorEnemigo?.nombre).toBe(nombreJugador2)
expect(response.payload.jugadorEnemigo?.nBarrera).toBe(MAX_BARRERA_CARDS)
expect(response.payload.jugadorEnemigo?.nMano).toBe(MAX_MANO_CARDS)
expect(response.payload.jugadorEnemigo?.enTurno).toBe(false)
expect(response.payload.jugadorEnemigo?.nDeck).toBe(MAX_DECK - MAX_BARRERA_CARDS - MAX_MANO_CARDS)
})
const player2actions = request(server)
.ws('/ws')
.expectJson((response: IniciarJuegoResponse) => { // response: jugador 1 inició el juego
expect(response.event).toBe(WebsocketEventTitle.INICIAR_JUEGO)
expect(response.payload.respuesta).toBe(ResultadoIniciarJuego.JUEGO_INICIADO)
expect(response.payload.jugador?.nombre).toBe(nombreJugador2)
expect(response.payload.jugador?.nBarrera).toBe(MAX_BARRERA_CARDS)
expect(response.payload.jugador?.nDeck).toBe(MAX_DECK - MAX_BARRERA_CARDS - MAX_MANO_CARDS)
expect(response.payload.jugador?.mano.length).toBe(MAX_MANO_CARDS)
expect(response.payload.jugador?.enTurno).toBe(false)
expect(response.payload.jugadorEnemigo?.nombre).toBe(nombreJugador1)
expect(response.payload.jugadorEnemigo?.nBarrera).toBe(MAX_BARRERA_CARDS)
expect(response.payload.jugadorEnemigo?.nDeck).toBe(MAX_DECK - MAX_BARRERA_CARDS - MAX_MANO_CARDS)
expect(response.payload.jugadorEnemigo?.nMano).toBe(MAX_MANO_CARDS)
expect(response.payload.jugadorEnemigo?.enTurno).toBe(true)
})
await Promise.all([
player1actions,
player2actions
])
}) Result
|
I am getting a loss of variable values when I make a long request as in the attached case, which causes you to get expected errors for not sending the correct data. In this specific case, the "jugadorId1" variable is set its value in the first expectJson and used in subsequent sendJson without problems except in the last one where the variable loses its value and returns to its empty default value (""). For this reason, my test fails. My belief is that the library has problems with long requests.
Error
The project is public and the file in question can be consulted at the following address: https://github.com/xsrpm/battlecard/blob/master/api/src/tests/server/websocket-acciones/cambiar-posicion.test.ts
The text was updated successfully, but these errors were encountered: