Skip to content
This repository has been archived by the owner on May 1, 2023. It is now read-only.

feat: add a11y violations model #104

Merged
merged 1 commit into from
Aug 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""create a11y_violations table

Revision ID: 4b61e9319ad9
Revises: e251ec3b0f77
Create Date: 2021-08-24 21:30:09.916966

"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision = "4b61e9319ad9"
down_revision = "e251ec3b0f77"
branch_labels = None
depends_on = None


def upgrade():
op.create_table(
"a11y_violations",
sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True),
sa.Column("a11y_report_id", postgresql.UUID(as_uuid=True), nullable=False),
sa.Column("violation", sa.String(), nullable=False),
sa.Column("impact", sa.String(), nullable=False),
sa.Column("target", sa.Text()),
sa.Column("html", sa.Text()),
sa.Column("data", postgresql.JSONB(), nullable=False),
sa.Column("tags", postgresql.JSONB(), nullable=False),
sa.Column("message", sa.Text()),
sa.Column("url", sa.String()),
sa.Column("created_at", sa.DateTime, default=sa.func.utc_timestamp()),
sa.Column("updated_at", sa.DateTime, onupdate=sa.func.utc_timestamp()),
sa.ForeignKeyConstraint(
["a11y_report_id"],
["a11y_reports.id"],
),
)


def downgrade():
op.drop_table("a11y_violations")
2 changes: 2 additions & 0 deletions api/models/A11yReport.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class A11yReport(Base):
)
scan = relationship("Scan", back_populates="a11y_reports")

a11y_violations = relationship("A11yViolation")

@validates("product")
def validate_product(self, _key, value):
assert value != ""
Expand Down
61 changes: 61 additions & 0 deletions api/models/A11yViolation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import datetime
import uuid

from sqlalchemy import DateTime, Column, ForeignKey, String, Text
from sqlalchemy.dialects.postgresql import JSONB, UUID
from sqlalchemy.orm import relationship, validates

from models import Base
from models.A11yReport import A11yReport


class A11yViolation(Base):
__tablename__ = "a11y_violations"

id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
violation = Column(String, nullable=False)
impact = Column(String, nullable=False)
target = Column(Text)
html = Column(Text)
data = Column(JSONB, nullable=False)
tags = Column(JSONB, nullable=False)
message = Column(Text)
url = Column(String)
created_at = Column(
DateTime,
index=False,
unique=False,
nullable=False,
default=datetime.datetime.utcnow,
)
updated_at = Column(
DateTime,
index=False,
unique=False,
nullable=True,
onupdate=datetime.datetime.utcnow,
)
a11y_report_id = Column(
UUID(as_uuid=True), ForeignKey(A11yReport.id), index=True, nullable=False
)
a11y_report = relationship("A11yReport", back_populates="a11y_violations")

@validates("violation")
def validate_violation(self, _key, value):
assert value != ""
return value

@validates("impact")
def validate_impact(self, _key, value):
assert value != ""
return value

@validates("data")
def validate_data(self, _key, value):
assert value != ""
return value

@validates("tags")
def validate_tags(self, _key, value):
assert value != ""
return value
15 changes: 15 additions & 0 deletions api/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from alembic.config import Config
from alembic import command

from models.A11yReport import A11yReport
from models.Organisation import Organisation
from models.Scan import Scan
from models.ScanType import ScanType
Expand All @@ -15,6 +16,20 @@
from sqlalchemy.orm import sessionmaker


@pytest.fixture(scope="session")
def a11y_report_fixture(session, scan_fixture):
a11y_report = A11yReport(
product="product",
revision="revision",
url="url",
summary={"jsonb": "data"},
scan=scan_fixture,
)
session.add(a11y_report)
session.commit()
return a11y_report


@pytest.fixture
def assert_new_model_saved():
def f(model):
Expand Down
154 changes: 154 additions & 0 deletions api/tests/models/test_A11yViolation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import pytest

from sqlalchemy.exc import IntegrityError


from models.A11yViolation import A11yViolation


def test_a11y_violation_belongs_to_an_a11y_report(a11y_report_fixture, session):
a11y_violation = A11yViolation(
violation="violation",
impact="impact",
target="target",
html="html",
data={"jsonb": "data"},
tags={"jsonb": "tags"},
message="message",
url="url",
a11y_report=a11y_report_fixture,
)
session.add(a11y_violation)
session.commit()
assert a11y_report_fixture.a11y_violations[-1].id == a11y_violation.id
session.delete(a11y_violation)
session.commit()


def test_a11y_violation_model(a11y_report_fixture):
a11y_violation = A11yViolation(
violation="violation",
impact="impact",
target="target",
html="html",
data={"jsonb": "data"},
tags={"jsonb": "tags"},
message="message",
url="url",
a11y_report=a11y_report_fixture,
)
assert a11y_violation.violation == "violation"
assert a11y_violation.impact == "impact"
assert a11y_violation.target == "target"
assert a11y_violation.html == "html"
assert a11y_violation.data == {"jsonb": "data"}
assert a11y_violation.tags == {"jsonb": "tags"}
assert a11y_violation.message == "message"
assert a11y_violation.url == "url"
assert a11y_violation.a11y_report is not None


def test_a11y_violation_model_saved(
assert_new_model_saved, a11y_report_fixture, session
):
a11y_violation = A11yViolation(
violation="violation",
impact="impact",
target="target",
html="html",
data={"jsonb": "data"},
tags={"jsonb": "tags"},
message="message",
url="url",
a11y_report=a11y_report_fixture,
)
session.add(a11y_violation)
session.commit()
assert a11y_violation.violation == "violation"
assert a11y_violation.impact == "impact"
assert a11y_violation.target == "target"
assert a11y_violation.html == "html"
assert_new_model_saved(a11y_violation)
assert a11y_violation.data == {"jsonb": "data"}
assert a11y_violation.tags == {"jsonb": "tags"}
assert a11y_violation.message == "message"
assert a11y_violation.url == "url"
session.delete(a11y_violation)
session.commit()


def test_a11y_violation_empty_violation_fails(a11y_report_fixture, session):
a11y_violation = A11yViolation(
impact="impact",
target="target",
html="html",
data={"jsonb": "data"},
tags={"jsonb": "tags"},
message="message",
url="url",
a11y_report=a11y_report_fixture,
)
session.add(a11y_violation)
with pytest.raises(IntegrityError):
session.commit()
session.rollback()


def test_a11y_violation_empty_impact_fails(a11y_report_fixture, session):
a11y_violation = A11yViolation(
violation="violation",
data={"jsonb": "data"},
tags={"jsonb": "tags"},
message="message",
url="url",
a11y_report=a11y_report_fixture,
)
session.add(a11y_violation)
with pytest.raises(IntegrityError):
session.commit()
session.rollback()


def test_a11y_violation_empty_data_fails(a11y_report_fixture, session):
a11y_violation = A11yViolation(
violation="violation",
impact="impact",
target="target",
tags={"jsonb": "tags"},
a11y_report=a11y_report_fixture,
)
session.add(a11y_violation)
with pytest.raises(IntegrityError):
session.commit()
session.rollback()


def test_a11y_violation_empty_tags_fails(a11y_report_fixture, session):
a11y_violation = A11yViolation(
violation="violation",
impact="impact",
target="target",
data={"jsonb": "data"},
a11y_report=a11y_report_fixture,
)
session.add(a11y_violation)
with pytest.raises(IntegrityError):
session.commit()
session.rollback()


def test_a11y_violation_empty_a11y_report_fails(session):
a11y_violation = A11yViolation(
violation="violation",
impact="impact",
target="target",
html="html",
data={"jsonb": "data"},
tags={"jsonb": "tags"},
message="message",
url="url",
)
session.add(a11y_violation)
with pytest.raises(IntegrityError):
session.commit()
session.rollback()