Skip to content

Commit

Permalink
Merge branch 'master' into mathesar-433-duration-display-options
Browse files Browse the repository at this point in the history
  • Loading branch information
silentninja committed Feb 24, 2022
2 parents 9b7acc8 + 8591a14 commit e124ca2
Show file tree
Hide file tree
Showing 15 changed files with 286 additions and 65 deletions.
40 changes: 1 addition & 39 deletions mathesar/tests/api/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@
from sqlalchemy import Table as SATable

from db.types import base, install
from db.schemas.operations.create import create_schema as create_sa_schema
from db.schemas.utils import get_schema_oid_from_name, get_schema_name_from_oid
from db.tables.operations.select import get_oid_from_table
from mathesar.database.base import create_mathesar_engine
from mathesar.imports.csv import create_table_from_csv
from mathesar.models import Schema, Table, DataFile
from mathesar.models import Table, DataFile


TEST_SCHEMA = 'import_csv_schema'
Expand All @@ -23,31 +21,6 @@ def client():
return APIClient()


@pytest.fixture
def create_schema(engine, test_db_model):
"""
Creates a schema factory, making sure to track and clean up new instances
"""
function_schemas = {}

def _create_schema(schema_name):
if schema_name in function_schemas:
schema_oid = function_schemas[schema_name]
else:
create_sa_schema(schema_name, engine)
schema_oid = get_schema_oid_from_name(schema_name, engine)
function_schemas[schema_name] = schema_oid
schema_model, _ = Schema.current_objects.get_or_create(oid=schema_oid, database=test_db_model)
return schema_model
yield _create_schema

for oid in function_schemas.values():
# Handle schemas being renamed during test
schema = get_schema_name_from_oid(oid, engine)
with engine.begin() as conn:
conn.execute(text(f'DROP SCHEMA IF EXISTS "{schema}" CASCADE;'))


@pytest.fixture
def create_data_file():
def _create_data_file(file_path, file_name):
Expand All @@ -59,17 +32,6 @@ def _create_data_file(file_path, file_name):
return _create_data_file


@pytest.fixture
def create_table(csv_filename, create_schema):
with open(csv_filename, 'rb') as csv_file:
data_file = DataFile.objects.create(file=File(csv_file))

def _create_table(table_name, schema='Patents'):
schema_model = create_schema(schema)
return create_table_from_csv(data_file, table_name, schema_model)
return _create_table


@pytest.fixture
def create_data_types_table(data_types_csv_filename, create_schema):
with open(data_types_csv_filename, 'rb') as csv_file:
Expand Down
43 changes: 43 additions & 0 deletions mathesar/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
from django.core.files import File
"""
This inherits the fixtures in the root conftest.py
"""
import pytest

from sqlalchemy import text

from db.schemas.operations.create import create_schema as create_sa_schema
from db.schemas.utils import get_schema_oid_from_name, get_schema_name_from_oid
from mathesar.imports.csv import create_table_from_csv
from mathesar.models import Database
from mathesar.models import Schema, DataFile


@pytest.fixture(scope="session", autouse=True)
Expand Down Expand Up @@ -87,3 +94,39 @@ def data_types_csv_filename():
@pytest.fixture(scope='session')
def non_unicode_csv_filename():
return 'mathesar/tests/data/non_unicode_files/utf_16_le.csv'


@pytest.fixture
def create_schema(engine, test_db_model):
"""
Creates a schema factory, making sure to track and clean up new instances
"""
function_schemas = {}

def _create_schema(schema_name):
if schema_name in function_schemas:
schema_oid = function_schemas[schema_name]
else:
create_sa_schema(schema_name, engine)
schema_oid = get_schema_oid_from_name(schema_name, engine)
function_schemas[schema_name] = schema_oid
schema_model, _ = Schema.current_objects.get_or_create(oid=schema_oid, database=test_db_model)
return schema_model
yield _create_schema

for oid in function_schemas.values():
# Handle schemas being renamed during test
schema = get_schema_name_from_oid(oid, engine)
with engine.begin() as conn:
conn.execute(text(f'DROP SCHEMA IF EXISTS "{schema}" CASCADE;'))


@pytest.fixture
def create_table(csv_filename, create_schema):
with open(csv_filename, 'rb') as csv_file:
data_file = DataFile.objects.create(file=File(csv_file))

def _create_table(table_name, schema='Patents'):
schema_model = create_schema(schema)
return create_table_from_csv(data_file, table_name, schema_model)
return _create_table
21 changes: 21 additions & 0 deletions mathesar/tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from db.schemas.operations.create import create_schema as create_sa_schema
from db.schemas.utils import get_schema_name_from_oid, get_schema_oid_from_name
from mathesar.models import Database, Schema
from mathesar.tests.integration.utils.locators import get_table_entry

TEST_SCHEMA = 'import_csv_schema'
PATENT_SCHEMA = 'Patents'
Expand Down Expand Up @@ -67,3 +68,23 @@ def schema(create_schema, schema_name):
@pytest.fixture
def base_schema_url(schema, live_server):
return f"{live_server}/{schema.database.name}/{schema.id}"


@pytest.fixture
def schemas_page_url(live_server, test_db_name):
return f"{live_server}/{test_db_name}/schemas/"


@pytest.fixture
def go_to_patents_data_table(page, create_table, schema_name, base_schema_url):
"""
Imports the `patents.csv` data into a table named "patents" and navigates to
the view of that table before starting the test.
"""
table_name = "patents"
table = create_table(table_name, schema_name)
table.import_verified = True
table.save()
page.goto(base_schema_url)
get_table_entry(page, table_name).click()
yield table_name
10 changes: 10 additions & 0 deletions mathesar/tests/integration/test_columns.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from playwright.sync_api import expect


def test_add_column(page, go_to_patents_data_table):
page.click("button[aria-label='New Column']")
column_name = "TEST"
page.fill(".new-column-dropdown input", column_name)
page.click("button:has-text('Add')")
column_header = f".table-content .header .cell .name:has-text('{column_name}')"
expect(page.locator(column_header)).to_be_visible()
32 changes: 32 additions & 0 deletions mathesar/tests/integration/test_constraints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from playwright.sync_api import expect


def test_add_and_remove_multi_column_unique_constraint(page, go_to_patents_data_table):
# Add
page.click("[aria-label='Table Actions']")
page.click("text=Constraints")
page.click("[aria-label='New Constraint']")
page.click("button:has-text('Unique')")
page.click("fieldset >> text=Center")
page.click("fieldset >> text=Case Number")
page.click("button:has-text('Add')")
column_names = "Center, Case Number"
constraint = page.locator(
f".table-constraint:has(.type:has-text('unique')):has(.columns:has-text('{column_names}'))"
)
expect(page.locator("text=Table Constraints (2)")).to_be_visible()
expect(constraint).to_be_visible()

# Remove
constraint.locator(".drop button").click()
page.click("button:has-text('Delete Constraint')")
expect(constraint).not_to_be_visible()
expect(page.locator("text=Table Constraints (1)")).to_be_visible()


def test_try_to_dissallow_null_for_column_with_null_values(page, go_to_patents_data_table):
page.click("button:has-text('Patent Number')")
allow_null = page.locator("button:has-text('Allow NULL')")
allow_null.click()
expect(page.locator(".toast-item:has-text('Unable to update')")).to_be_visible()
expect(allow_null).to_be_visible()
36 changes: 14 additions & 22 deletions mathesar/tests/integration/test_imports.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,25 @@
from playwright.sync_api import Page, expect
from playwright.sync_api import expect

from mathesar.tests.integration.utils.locators import get_table_entry, get_tables_list

def get_tables_list(page: Page):
return page.locator("#sidebar li[aria-level='1']:has(button:has-text('Tables')) ul")


def get_table_entry(tables_list, table_name):
return tables_list.locator(f"li:has-text('{table_name}')")


def test_create_empty_table(page: Page, base_schema_url):
def test_import_from_clipboard(page, base_schema_url):
page.goto(base_schema_url)
tables_list = get_tables_list(page)
expect(tables_list).to_be_empty()
expect(get_tables_list(page)).to_be_empty()
page.click("[aria-label='New Table']")
page.click("button:has-text('Empty Table')")
table_entry = get_table_entry(tables_list, "Table 0")
expect(table_entry).to_be_visible()
page.click("button:has-text('Import Data')")
page.click("text=Copy and Paste Text")
page.fill("textarea", "foo,bar\n2,3")
page.click("button:has-text('Continue')")
page.click("button:has-text('Finish Import')")
expect(get_table_entry(page, "Table 0")).to_be_visible()


def test_import_from_clipboard(page: Page, base_schema_url):
def test_import_from_file(page, base_schema_url):
page.goto(base_schema_url)
tables_list = get_tables_list(page)
expect(tables_list).to_be_empty()
page.click("[aria-label='New Table']")
page.click("button:has-text('Import Data')")
page.click("text=Copy and Paste Text")
page.fill("textarea", "foo,bar\n2,3")
page.click("button:has-text('Continue')")
page.set_input_files(".file-upload input", "/code/mathesar/tests/data/patents.csv")
page.click("button:has-text('Finish Import')")
table_entry = get_table_entry(tables_list, "Table 0")
expect(table_entry).to_be_visible()
# "1393 records" is part of the text shown below the table near the pager
expect(page.locator("text=1393 records")).to_be_visible()
49 changes: 49 additions & 0 deletions mathesar/tests/integration/test_records.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import re

from playwright.sync_api import expect

first_pk_cell_in_table = ".row .cell.is-pk >> nth=0"


def test_add_row(page, go_to_patents_data_table):
# Note: This is the New Record button at the top of the table. I also tried
# to write a separate test for adding a row from the row placeholder at the
# bottom of the table, but that proved difficult to write because of the
# VirtualList so I abandoned it.
page.click("button:has-text('New Record')")
expect(page.locator(".row.done .cell.is-pk:has-text('1394')")).to_be_visible()


def test_sort_table_by_column(page, go_to_patents_data_table):
page.click("button:has-text('Title')")
page.click("button:has-text('Sort Descending')")
page.click("button:has-text('Status')")
page.click("button:has-text('Sort Ascending')")
expect(page.locator(first_pk_cell_in_table)).to_have_text("729")


def test_increment_pagination(page, go_to_patents_data_table):
page.click("[aria-label='Goto Page 2']")
expect(page.locator(first_pk_cell_in_table)).to_have_text("501")


def test_edit_cell(page, go_to_patents_data_table):
row = page.locator(".row:has-text('ARC-14231-3')")
cell = row.locator(".cell:has-text('Issued')")
input = cell.locator("input")
all_changes_saved = page.locator("text=All changes saved")
cell.dblclick()
input.fill("TEST")
page.keyboard.press("Enter")
expect(all_changes_saved).to_be_visible()
expect(row).to_have_class(re.compile("updated"))


def test_delete_multiple_rows(page, go_to_patents_data_table):
page.hover(".row:has-text('ARC-14281-1')")
page.check(".row:has-text('ARC-14281-1') input[type='checkbox']")
page.hover(".row:has-text('ARC-14512-1')")
page.check(".row:has-text('ARC-14512-1') input[type='checkbox']")
page.click("button:has-text('Delete 2 records')")
expect(page.locator("text=ARC-14281-1")).not_to_be_visible()
expect(page.locator("text=ARC-14512-1")).not_to_be_visible()
18 changes: 18 additions & 0 deletions mathesar/tests/integration/test_schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from playwright.sync_api import expect


def test_create_and_delete_schema(page, schemas_page_url):
page.goto(schemas_page_url)
schema_name = "foo"
schema_entry = page.locator(f".schema-list .schema-row:has-text('{schema_name}')")
expect(schema_entry).not_to_be_visible()
page.click("text=New Schema")
page.fill("[aria-label='name']", schema_name)
page.click("button:has-text('Save')")
expect(schema_entry).to_be_visible()
# We're also deleting the schema in the same test as a way of cleaning up
# the state created in this test so as not to interfer with other tests.
# This is a hack for now.
schema_entry.locator("button[aria-label='Delete Schema']").click()
page.click("button:has-text('Delete Schema')")
expect(schema_entry).not_to_be_visible()
11 changes: 11 additions & 0 deletions mathesar/tests/integration/test_tables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from playwright.sync_api import expect

from mathesar.tests.integration.utils.locators import get_table_entry, get_tables_list


def test_create_empty_table(page, base_schema_url):
page.goto(base_schema_url)
expect(get_tables_list(page)).to_be_empty()
page.click("[aria-label='New Table']")
page.click("button:has-text('Empty Table')")
expect(get_table_entry(page, "Table 0")).to_be_visible()
72 changes: 72 additions & 0 deletions mathesar/tests/integration/test_ui.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import re
from playwright.sync_api import expect, Locator
from mathesar.tests.integration.utils.locators import get_table_entry


def create_new_empty_table(page):
page.click("[aria-label='New Table']")
page.click("button:has-text('Empty Table')")


def get_tab(page, tab_text):
return page.locator(
f".tab-container [role=tablist] [role=presentation]:has-text('{tab_text}')"
)


def close_tab(tab_locator: Locator):
tab_locator.hover()
tab_locator.locator("[aria-label=remove]").click()


def test_tabs(page, base_schema_url):
page.goto(base_schema_url)

# Create Table 0
create_new_empty_table(page)
table_0_entry = get_table_entry(page, "Table 0")
table_0_tab = get_tab(page, "Table 0")
close_tab(table_0_tab)

# Create Table 1
create_new_empty_table(page)
table_1_entry = get_table_entry(page, "Table 1")
table_1_tab = get_tab(page, "Table 1")
close_tab(table_1_tab)

# No tabs should be open
expect(table_0_tab).not_to_be_visible()
expect(table_1_tab).not_to_be_visible()

# Open Table 0
table_0_entry.click()
expect(table_0_entry.locator(".item")).to_have_class(re.compile("active"))
expect(table_0_tab).to_have_class(re.compile("active"))

# Open Table 1
table_1_entry.click()
expect(table_0_entry.locator(".item")).not_to_have_class(re.compile("active"))
expect(table_1_entry.locator(".item")).to_have_class(re.compile("active"))
expect(table_0_tab).not_to_have_class(re.compile("active"))
expect(table_1_tab).to_have_class(re.compile("active"))

# Switch to tab for Table 0
table_0_tab.click()
expect(table_0_entry.locator(".item")).to_have_class(re.compile("active"))
expect(table_1_entry.locator(".item")).not_to_have_class(re.compile("active"))
expect(table_0_tab).to_have_class(re.compile("active"))
expect(table_1_tab).not_to_have_class(re.compile("active"))

# Close tab for Table 0
close_tab(table_0_tab)
expect(table_0_entry.locator(".item")).not_to_have_class(re.compile("active"))
expect(table_1_entry.locator(".item")).to_have_class(re.compile("active"))
expect(table_0_tab).not_to_be_visible()
expect(table_1_tab).to_have_class(re.compile("active"))

# Close tab for Table 1
close_tab(table_1_tab)
expect(table_0_entry.locator(".item")).not_to_have_class(re.compile("active"))
expect(table_1_entry.locator(".item")).not_to_have_class(re.compile("active"))
expect(table_0_tab).not_to_be_visible()
expect(table_1_tab).not_to_be_visible()
Loading

0 comments on commit e124ca2

Please sign in to comment.