Skip to content

Commit 191c5ec

Browse files
rdhyeeclaude
andauthored
Add xfail test stubs for wireframe features (#105)
* Add 52 xfail test stubs covering all wireframe features (#104) Structured as Gherkin-ready features/scenarios for future pytest-bdd migration. Each test is marked xfail("Not yet tested") and organized by page: homepage, about, research, vocabularies, tutorials, navbar dropdowns, footer/links, and responsive layout. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Promote 49 passing tests from xfail to real regression guards Ran all 52 stubs against live site: 41 already passed (now active), 8 dropdown tests fixed (hover→click for Bootstrap 5), leaving only 3 genuine xfails for remaining wireframe work: - Homepage showcase needs 4 images - Vocabulary detail needs concept hierarchy - Vocabulary detail needs concept definitions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b08ad6e commit 191c5ec

8 files changed

Lines changed: 528 additions & 0 deletions

tests/test_about_features.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
"""
2+
Feature: About Page
3+
As a visitor learning about iSamples
4+
I want to navigate to specific sections via anchors
5+
And see team photos and PI information
6+
So that I understand who is behind the project
7+
8+
Wireframe ref: Figma frame [33:919] About
9+
"""
10+
from conftest import SITE_URL
11+
12+
13+
class TestAboutAnchors:
14+
"""Scenario: Section anchors scroll to correct content."""
15+
16+
def test_team_anchor_scrolls_to_team(self, page):
17+
"""Given I navigate to about.html#team, Then the Team section is visible."""
18+
page.goto(f"{SITE_URL}/about.html#team", wait_until="domcontentloaded")
19+
heading = page.locator("h2:has-text('Team')")
20+
assert heading.count() > 0
21+
assert heading.first.is_visible()
22+
23+
def test_photo_gallery_anchor(self, page):
24+
"""Given I navigate to about.html#photo-gallery, Then the Photo Gallery is visible."""
25+
page.goto(f"{SITE_URL}/about.html#photo-gallery", wait_until="domcontentloaded")
26+
heading = page.locator("h2:has-text('Photo Gallery')")
27+
assert heading.count() > 0
28+
assert heading.first.is_visible()
29+
30+
def test_background_anchor(self, page):
31+
"""Given I navigate to about.html#background-history, Then Background section is visible."""
32+
page.goto(f"{SITE_URL}/about.html#background-history", wait_until="domcontentloaded")
33+
heading = page.locator("h2:has-text('Background')")
34+
assert heading.count() > 0
35+
36+
37+
class TestAboutPILinks:
38+
"""Scenario: PI names link to ORCID profiles."""
39+
40+
def test_pi_names_have_orcid_links(self, page):
41+
"""Given I am on the about page, Then each PI name links to an ORCID profile."""
42+
page.goto(f"{SITE_URL}/about.html", wait_until="domcontentloaded")
43+
orcid_links = page.locator("a[href*='orcid.org']")
44+
assert orcid_links.count() >= 4, f"Expected 4 ORCID links, found {orcid_links.count()}"
45+
46+
47+
class TestAboutGallery:
48+
"""Scenario: Photo gallery displays workshop and facility images."""
49+
50+
def test_gallery_has_images(self, page):
51+
"""Given I am on the about page, Then the photo gallery has at least 6 images."""
52+
page.goto(f"{SITE_URL}/about.html#photo-gallery", wait_until="domcontentloaded")
53+
gallery_section = page.locator("#photo-gallery ~ div img, #photo-gallery ~ .columns img")
54+
# Fallback: count all images near the gallery heading
55+
if gallery_section.count() == 0:
56+
gallery_section = page.locator("img[src*='gallery'], img[src*='workshop'], img[src*='tucson'], img[src*='smithsonian']")
57+
assert gallery_section.count() >= 3, f"Expected gallery images, found {gallery_section.count()}"
58+
59+
60+
class TestAboutContributors:
61+
"""Scenario: Contributors section lists project participants."""
62+
63+
def test_contributors_section_expandable(self, page):
64+
"""Given I am on the about page, Then I can expand the Contributors section."""
65+
page.goto(f"{SITE_URL}/about.html", wait_until="domcontentloaded")
66+
assert page.get_by_text("Contributors").count() > 0

tests/test_footer_links.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
"""
2+
Feature: Footer and External Links
3+
As a visitor on any page
4+
I want to see consistent footer information and working external links
5+
So that I can find funding info, legal notices, and related resources
6+
7+
Wireframe ref: Figma frame [33:425] (footer visible on all frames)
8+
"""
9+
from conftest import SITE_URL
10+
11+
12+
class TestFooterContent:
13+
"""Scenario: Footer displays NSF funding acknowledgement."""
14+
15+
def test_footer_has_nsf_grant_numbers(self, page):
16+
"""Given I am on any page, Then I see NSF grant numbers in the footer."""
17+
page.goto(SITE_URL, wait_until="domcontentloaded")
18+
footer = page.locator("footer, .page-footer")
19+
assert footer.get_by_text("2004839").count() > 0
20+
21+
def test_footer_has_copyright(self, page):
22+
"""And the footer contains a copyright notice."""
23+
page.goto(SITE_URL, wait_until="domcontentloaded")
24+
footer = page.locator("footer, .page-footer")
25+
assert footer.get_by_text("Copyright").count() > 0
26+
27+
def test_footer_has_disclaimer(self, page):
28+
"""And the footer includes the NSF disclaimer."""
29+
page.goto(SITE_URL, wait_until="domcontentloaded")
30+
footer = page.locator("footer, .page-footer")
31+
assert footer.get_by_text("not necessarily reflect").count() > 0
32+
33+
34+
class TestExternalLinks:
35+
"""Scenario: Navbar external links point to correct destinations."""
36+
37+
def test_github_icon_links_to_isamplesorg(self, page):
38+
"""Given I am on any page, Then the GitHub icon links to isamplesorg."""
39+
page.goto(SITE_URL, wait_until="domcontentloaded")
40+
gh_link = page.locator("a[href*='github.com/isamplesorg']").first
41+
assert gh_link is not None
42+
href = gh_link.get_attribute("href")
43+
assert "github.com/isamplesorg" in href
44+
45+
def test_slack_icon_links_to_workspace(self, page):
46+
"""And the Slack icon links to the iSamples workspace."""
47+
page.goto(SITE_URL, wait_until="domcontentloaded")
48+
slack_link = page.locator("a[href*='isamples.slack.com']")
49+
assert slack_link.count() > 0
50+
51+
52+
class TestMetadataModelLink:
53+
"""Scenario: Metadata Model external link opens correctly."""
54+
55+
def test_metadata_model_link_exists(self, page):
56+
"""Given I navigate to Architecture, Then Metadata Model links to external site."""
57+
page.goto(f"{SITE_URL}/design/index.html", wait_until="domcontentloaded")
58+
link = page.locator("a[href*='isamplesorg.github.io/metadata']")
59+
assert link.count() > 0

tests/test_homepage_features.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
"""
2+
Feature: Homepage
3+
As a visitor to iSamples.org
4+
I want to see an engaging overview of the project
5+
So that I understand what iSamples offers and can start exploring
6+
7+
Wireframe ref: Figma frame [33:425] Home
8+
"""
9+
import pytest
10+
from conftest import SITE_URL
11+
12+
13+
class TestHomepageShowcase:
14+
"""Scenario: Showcase gallery displays real sample images."""
15+
16+
@pytest.mark.xfail(reason="Not yet tested: #104 P0 — showcase gallery")
17+
def test_showcase_has_four_images(self, page):
18+
"""Given I am on the homepage, Then I should see 4 showcase images."""
19+
page.goto(SITE_URL, wait_until="domcontentloaded")
20+
images = page.locator(".quarto-figure img, .lightbox img")
21+
assert images.count() >= 4
22+
23+
def test_showcase_images_have_alt_text(self, page):
24+
"""And each showcase image should have alt text."""
25+
page.goto(SITE_URL, wait_until="domcontentloaded")
26+
images = page.locator(".quarto-figure img, .lightbox img")
27+
for i in range(images.count()):
28+
alt = images.nth(i).get_attribute("alt")
29+
assert alt and len(alt) > 0, f"Image {i} missing alt text"
30+
31+
32+
class TestHomepageCallouts:
33+
"""Scenario: Collapsible callouts explain the project."""
34+
35+
def test_has_what_is_isamples_callout(self, page):
36+
"""Given I am on the homepage, Then I should see a 'What is iSamples?' callout."""
37+
page.goto(SITE_URL, wait_until="domcontentloaded")
38+
assert page.get_by_text("What is iSamples").count() > 0
39+
40+
def test_has_how_can_i_access_callout(self, page):
41+
"""And I should see a 'How can I access it?' callout."""
42+
page.goto(SITE_URL, wait_until="domcontentloaded")
43+
assert page.get_by_text("How can I access").count() > 0
44+
45+
def test_has_why_browser_based_callout(self, page):
46+
"""And I should see a 'Why browser-based?' callout."""
47+
page.goto(SITE_URL, wait_until="domcontentloaded")
48+
assert page.get_by_text("Why browser-based").count() > 0
49+
50+
51+
class TestHomepageHero:
52+
"""Scenario: Hero section draws visitors in."""
53+
54+
def test_hero_shows_sample_count(self, page):
55+
"""Given I am on the homepage, Then I should see '6.7 million' in the stats."""
56+
page.goto(SITE_URL, wait_until="domcontentloaded")
57+
assert page.get_by_text("6.7 million").count() > 0
58+
59+
def test_hero_shows_repository_count(self, page):
60+
"""And I should see '4 repositories'."""
61+
page.goto(SITE_URL, wait_until="domcontentloaded")
62+
assert page.get_by_text("4 repositories").count() > 0

tests/test_navbar_dropdowns.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
"""
2+
Feature: Navbar Dropdown Menus
3+
As a visitor navigating iSamples
4+
I want dropdown menus on the navbar to reveal sub-pages
5+
So that I can quickly reach any section without using the sidebar
6+
7+
Wireframe ref: Figma frame [33:425] Home (6-item navbar)
8+
Implementation: PR #103
9+
"""
10+
from conftest import SITE_URL
11+
12+
13+
def _open_dropdown(page, label, exact=False):
14+
"""Click a Bootstrap 5 navbar dropdown toggle to reveal its menu."""
15+
# Structure: li.nav-item.dropdown > a.dropdown-toggle > span.menu-text
16+
dropdown_li = page.locator(f".navbar li.dropdown:has(a:has-text('{label}'))")
17+
dropdown_li.locator("a.dropdown-toggle").click()
18+
menu = dropdown_li.locator("ul.dropdown-menu")
19+
menu.wait_for(state="visible", timeout=3000)
20+
return menu
21+
22+
23+
class TestHowToUseDropdown:
24+
"""Scenario: How to Use dropdown shows 5 sub-items."""
25+
26+
def test_how_to_use_dropdown_has_overview(self, page):
27+
"""Given I click How to Use, Then I see Overview."""
28+
page.goto(SITE_URL, wait_until="domcontentloaded")
29+
menu = _open_dropdown(page, "How to Use")
30+
assert menu.get_by_text("Overview").count() > 0
31+
32+
def test_how_to_use_dropdown_has_deep_dive(self, page):
33+
"""And I see Deep-Dive Analysis."""
34+
page.goto(SITE_URL, wait_until="domcontentloaded")
35+
menu = _open_dropdown(page, "How to Use")
36+
assert menu.get_by_text("Deep-Dive Analysis").count() > 0
37+
38+
39+
class TestAboutDropdown:
40+
"""Scenario: About dropdown shows 4 sub-items."""
41+
42+
def test_about_dropdown_has_objectives(self, page):
43+
"""Given I click About, Then I see Objectives."""
44+
page.goto(SITE_URL, wait_until="domcontentloaded")
45+
menu = _open_dropdown(page, "About", exact=True)
46+
assert menu.get_by_text("Objectives").count() > 0
47+
48+
def test_about_dropdown_has_pis(self, page):
49+
"""And I see PIs and Contributors."""
50+
page.goto(SITE_URL, wait_until="domcontentloaded")
51+
menu = _open_dropdown(page, "About", exact=True)
52+
assert menu.get_by_text("PIs and Contributors").count() > 0
53+
54+
55+
class TestArchitectureDropdown:
56+
"""Scenario: Architecture & Vocabularies dropdown shows sub-items."""
57+
58+
def test_architecture_dropdown_has_requirements(self, page):
59+
"""Given I click Architecture, Then I see Requirements."""
60+
page.goto(SITE_URL, wait_until="domcontentloaded")
61+
menu = _open_dropdown(page, "Architecture")
62+
assert menu.get_by_text("Requirements").count() > 0
63+
64+
def test_architecture_dropdown_has_vocabularies(self, page):
65+
"""And I see Vocabularies."""
66+
page.goto(SITE_URL, wait_until="domcontentloaded")
67+
menu = _open_dropdown(page, "Architecture")
68+
assert menu.get_by_text("Vocabularies").count() > 0
69+
70+
71+
class TestResearchDropdown:
72+
"""Scenario: Research & Resources dropdown shows sub-items."""
73+
74+
def test_research_dropdown_has_publications(self, page):
75+
"""Given I click Research, Then I see Publications & Conferences."""
76+
page.goto(SITE_URL, wait_until="domcontentloaded")
77+
menu = _open_dropdown(page, "Research")
78+
assert menu.get_by_text("Publications").count() > 0
79+
80+
def test_research_dropdown_has_zenodo(self, page):
81+
"""And I see Zenodo Community."""
82+
page.goto(SITE_URL, wait_until="domcontentloaded")
83+
menu = _open_dropdown(page, "Research")
84+
assert menu.get_by_text("Zenodo").count() > 0

tests/test_research_resources.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
"""
2+
Feature: Research & Resources Page
3+
As a researcher interested in iSamples outputs
4+
I want to find publications, datasets, and source code in one place
5+
So that I can cite the project and build on its work
6+
7+
Wireframe ref: Figma frame [130:1156] Research & Resources
8+
"""
9+
from conftest import SITE_URL
10+
11+
12+
PUBS_URL = f"{SITE_URL}/pubs.html"
13+
14+
15+
class TestResearchPageSections:
16+
"""Scenario: All research sections appear on the unified page."""
17+
18+
def test_has_publications_section(self, page):
19+
"""Given I am on the research page, Then I see a Publications section."""
20+
page.goto(PUBS_URL, wait_until="domcontentloaded")
21+
assert page.locator("h2:has-text('Publications')").count() > 0
22+
23+
def test_has_zenodo_section(self, page):
24+
"""And I see a Zenodo Community section."""
25+
page.goto(PUBS_URL, wait_until="domcontentloaded")
26+
assert page.locator("h2:has-text('Zenodo')").count() > 0
27+
28+
def test_has_github_section(self, page):
29+
"""And I see a GitHub Repositories section."""
30+
page.goto(PUBS_URL, wait_until="domcontentloaded")
31+
assert page.locator("h2:has-text('GitHub')").count() > 0
32+
33+
def test_github_table_has_repos(self, page):
34+
"""And the GitHub section lists repository links."""
35+
page.goto(PUBS_URL, wait_until="domcontentloaded")
36+
repo_links = page.locator("a[href*='github.com/isamplesorg']")
37+
assert repo_links.count() >= 3
38+
39+
40+
class TestResearchMediaEmbeds:
41+
"""Scenario: Conference presentations are watchable and downloadable."""
42+
43+
def test_youtube_embed_is_responsive(self, page):
44+
"""Given I am on the research page, Then the YouTube embed has width/height."""
45+
page.goto(PUBS_URL, wait_until="domcontentloaded")
46+
iframe = page.locator("iframe[src*='youtube']")
47+
assert iframe.count() > 0
48+
box = iframe.first.bounding_box()
49+
assert box and box["width"] > 200
50+
51+
def test_pdf_embed_loads(self, page):
52+
"""And the PDF slides embed is present."""
53+
page.goto(PUBS_URL, wait_until="domcontentloaded")
54+
pdf = page.locator("embed[type='application/pdf']")
55+
assert pdf.count() > 0
56+
57+
def test_pdf_download_link(self, page):
58+
"""And a download link for the PDF slides exists."""
59+
page.goto(PUBS_URL, wait_until="domcontentloaded")
60+
download = page.locator("a[href*='.pdf']:has-text('Download')")
61+
assert download.count() > 0
62+
63+
64+
class TestResearchBibliography:
65+
"""Scenario: Publications section renders bibliography entries."""
66+
67+
def test_bibliography_has_entries(self, page):
68+
"""Given I am on the research page, Then I see at least one citation."""
69+
page.goto(PUBS_URL, wait_until="domcontentloaded")
70+
refs = page.locator("#refs .csl-entry, .references .csl-entry")
71+
assert refs.count() > 0

0 commit comments

Comments
 (0)