Splitting larger data heavy tests
# i-need-help
f
Hey folks, Thanks for everything you do for Cypress and for reading this post. I'm new to Cypress and I think I just need a little push in the right direction. I'm working on a multi language codebase and I'm testing both at the UI level and the API level. At the moment some of the API endpoints return all known data, other endpoints return some data for the key given. I'm not quite sure how best to format these tests. If I should have just one test that tests both global and key specific data, or if there's something I'm missing about Cypress that makes this easier. Hopefully that makes sense, let me know if you have any further questions. Any help is great
After some more time playing around, the use of aliases are cool but only exist within a specify/it function call which makes sense. I'm aware of the anti-pattern of trying to not use variables to get around this. I will go make a feature request for this, in the mean time I want to understand how this best fits with how Cypress should be used, what other means I should be thinking about. I was thinking about the idea of given an array, to repeat the same test or group of tests in a more clean way. If violating the norms, I would do something like this.
Copy code
[ "table", "of", "items" ].forEach((item)=>{
  it(`Item: ${item}`, ()=>{
    expect(item).to.be.a("string");
  })
})
I'm not a fan of the idea that I should have a fixture/table because the data is mutable, it doesn't feel right. I want to use data from within my application. So the best way felt like creating larger and larger single tests to cover both which also doesn't feel right.
This is all kind of nebulas and that maybe hasn't helped here. So there's two API endpoints called
/api/creatives
and
/api/creative/${uuid}
which I'm testing. Right now using a staging database to make sure all the basics are there, at a later stage I want to build up mocking and testing from a blank database upwards. Here's a sample of what I mean.
Copy code
js
describe("GET: api/creatives/", () => {
    beforeEach(() => {
        cy.fixture('defaultUserDetails').then((userDetails)=>{
            cy.session_login(userDetails.name, userDetails.user, userDetails.pass)
        })
    })
    it(`should return all non archived data`, () => {
        //cy.fixture('creatives_temp').then((response) => {
        cy.request("/api/creatives").then((response) => {
            expect(response.status).to.eq(200);
            expect(response.headers["content-type"]).to.eq("application/json");
            expect(response.body).to.be.a("array");

            return response.body
        }).then((data) => {
            data.forEach((element) => {
                cy.request(`/api/creative/${element.uuid}`).then((response)=>{
                    expect(response.status).to.eq(200);
                    expect(response.headers["content-type"]).to.eq("application/json");
                    expect(response.body).to.be.a("array");

                    return response.body
                }).then((specific)=>{
                    expect(element.id).to.be.a("number").be.finite.and.eq(specific.id);
                    expect(element.name).to.be.a("string").that.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i).and.eq(specific.name);
                    expect(element.uuid).to.be.a("string").that.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i).and.eq(specific.uuid);
                })
                
            })
        })
    })
})
This just doesn't feel like the right way to do it
g
f
These should be separate tests but I'm not entirely sure how to format it so it uses the right dats
g
and for checking responses, use cy-spok
f
Interesting thank you
How would you use something like this with an alias?
The docs don't immediately show it and I wonder how much Cypress will complain about it being out of scope. Only one way to find out ig
g
i don't see alias anywhere in your code sample though
f
It's not there because it's showing what I'm doing right now and it doesn't feel best practice to me
g
because the code is verbose?
f
Yes
I'm going to try it out anyway and see how it works, thank you for this
Okay it doesn't work as I thought.
Copy code
before(()=>{
  cy.fixture('creatives_temp').then((response) => {
    expect(response.status).to.eq(200);
      expect(response.headers["content-type"]).to.eq("application/json");
      expect(response.body).to.be.a("array");

      return response.body
  }).as("test_state")
})
it.each(cy.get("@test_state"))("Test %s", (item)=>{
  cy.log(item)
})
Was my immediate thought
A fixture being used here to make it quicker to debug/test, exact same data as a normal http request
g
ohh, ok, all aliases are reset before each test. But I got you: https://github.com/bahmutov/cypress-aliases#as so in this case you would do
Copy code
js
before(()=>{
  cy.fixture('creatives_temp').then((response) => {
    expect(response.status).to.eq(200);
      expect(response.headers["content-type"]).to.eq("application/json");
      expect(response.body).to.be.a("array");

      return response.body
  }).as("test_state", {keep: true})
})
BUT: it still won't work because you cannot create additional tests when a test starts running (which is when
before
hook runs). Thus you would need to requests the data for example from your config file and pass it to the spec via
env
object. I show an example like this in my paid course lesson https://cypress.tips/courses/network-testing/lessons/bonus90
f
Epic okay, thank you for that