Testing

Why?

Ensures things work

Breaks functionality down to "testable chunks"

Catches breaks in the future

How

In python - UnitTest

In Javascript - Jest

For both - Cypress

How to organize tests

Start with the goal in mind

often easier to write test names upfront

Creating test suites for groupings

Think of this as an outline

Start as high level as possible

Text

Login works

A user can send a message

Higher level tests are more useful since they cover more

EG

Test happy path first, and start at the end

Test login returns 200 response

Test form fails to validate with missing email 

Test "success" string is contained in html

Text

Create Actual Result

actual = make_test_request.status

actual = model_Im_saving.objects.count()

How to structure a test

Test writing is MECHANICAL

Create Sample Data

In Django, this is through Model-Baker

In Javascript, this is through Mirage.js

This sample data is SPECIFIC to your test. As specific as you need. Opportunities for reuse will be obvious and occur as more writing happens

Create expected result

Often really simple: 

expected = 200 # server response

expected = "this is a success string" # happy string

expected = 0 # result of a count

Kick off smallest unit to create tested effect

Higher level tests kick off higher level flows

Most often a web request

Compare expected and actual

That's it. That's the test

class UserAdminTest(TestCase):
    def setUp(self):
        form_data = self.login_form_data = {
            "username": "ben@coolguy.com",
            "password": "yeahman",
        }
        self.user = baker.make_recipe(
            "hle.account.user",
            email=form_data["username"],
            is_superuser=True,
            is_staff=True,
            password=make_password(form_data["password"]),
        )

        self.client.login(
            username=self.login_form_data["username"],
            password=self.login_form_data["password"],
        )

    def test_user_admin_list(self):
        url = reverse("admin:account_user_changelist")
        response = self.client.get(url)
        actual = response.status_code
        expected = 200
        self.assertEqual(actual, expected)

Integration Testing

Integration testing pretends to be a user on a web page

Using scripted browser actions

Slow, so don't run by default

./manage.py test --tag=integration

How to create an integration test

PM uses the website to complete task, while using a recorder plugin

https://github.com/KabaLabs/Cypress-Recorder

    cy.visit('/login?next=/account');
    cy.get('[data-cy=login-email]')
      .click()
      .type('ben@lightmatter.com')
      .get('[data-cy=login-password]')

      .type('asdfasdf')
      .get('[data-cy=submit-login]')
      .click();

    cy.location().should(location => {
      expect(location.pathname).to.eq('/account');
    });

PM Sends record to programmer

Programmer replaces sample data with precreated data

describe('Login page', () => {
  it('a user follows next login with the form', () => {
    cy.visit('/login?next=/account');
    cy.get('[data-cy=login-email]')
      .click()
      .type('jonnyrico@fednet.gov')
      .get('[data-cy=login-password]')

      .type('iwanttoknowmore')
      .get('[data-cy=submit-login]')
      .click();

    cy.location().should(location => {
      expect(location.pathname).to.eq('/account');
    });

    cy.get('#client-snackbar').should('contain', 'Successfully logged in');
  });
});
class RegistrationCypressTest(NextjsCypressTest):

    def test_login(self):
        self.user = baker.make_recipe(
        	User,
          	email="jonnyrico@fednet.gov",
          	password=make_password("iwanttoknowmore"),
        )
        result = self.run_cypress_test("login.js", silent=True, browser=False)
        self.assertEqual(result.returncode, 0)

Works by running a node server in a side process of django webapp

Javascript Snapshoting

Every render is saved and compared on file change.

Coverage testing

Useful to know you're doing it

Not by itself a guarantee tests are working