Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add heading tests and testbed #52

Merged
merged 5 commits into from
Oct 26, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/components/AppGallery.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ $cell: minmax(100px, 1fr);
}
}

// force no margins for children since grid already provides gap
.gallery :deep(*) {
margin: 0;
margin: 0 !important;
}
</style>
44 changes: 17 additions & 27 deletions src/components/AppHeading.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<component :is="tag || 'div'" ref="heading">
<component :is="tag || 'div'" ref="heading" :id="link">
<!-- heading content -->
<slot />

Expand Down Expand Up @@ -30,27 +30,22 @@ function setTag(this: Heading) {
}

// otherwise, determine automatically based on heading's position in document
// https://dequeuniversity.com/rules/axe/4.1/page-has-heading-one
else {
// heading element
const element = this?.$refs?.heading as HTMLElement;
// parent section element
const section = element.closest("section") as HTMLElement;
// is there an existing h1 (besides self)
let h1 = document.querySelector("h1");
if (h1 === element) h1 = null;

// if heading is first element in section
if (element.matches(":first-child")) {
// if section is first section in <main> and if no other h1s already
// (only one h1 per page for accessibility)
if (section.matches(":first-child") && !h1) level = 1;
// if section is latter
else level = 2;
}
// if heading is latter
else {
level = 3;
}

// if heading is first in parent
const firstInParent = element.matches("*:first-child");
// if heading is first in document
const firstInDoc = element.matches(
"main > section:first-child > *:first-child, main > *:first-child"
);

// determine level
if (firstInDoc) level = 1;
else if (firstInParent) level = 2;
else level = 3;
}

// set tag/component
Expand All @@ -61,14 +56,9 @@ function setTag(this: Heading) {
function setLink(this: Heading) {
// heading element
const element = this?.$refs?.heading as HTMLElement;
// parent section element
const section = element.closest("section") as HTMLElement;

// if heading right at top of page, don't have link because no point
if (element.matches(":first-child") && section.matches(":first-child"))
this.link = "";
// otherwise, determine link from text content of heading
else this.link = kebabCase(element.innerText);

// determine link from text content of heading
this.link = kebabCase(element.textContent || "");
}

// heading component with anchor link and (optionally) automatic level
Expand Down
12 changes: 12 additions & 0 deletions src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Publications from "@/views/about/Publications.vue";
import Sources from "@/views/about/Sources.vue";
import Terms from "@/views/about/Terms.vue";
import Help from "@/views/help/Help.vue";
import Testbed from "@/views/Testbed.vue";
import { sleep } from "@/util/debug";

// handle redirect from 404
Expand Down Expand Up @@ -84,6 +85,17 @@ export const routes: Array<RouteRecordRaw> = [
name: "Help",
component: Help,
},

// test routes (pages to only include during development)
...(process.env.NODE_ENV === "development"
? [
{
path: "/testbed",
name: "Testbed",
component: Testbed,
},
]
: []),
];

const scrollBehavior: RouterScrollBehavior = async (
Expand Down
28 changes: 28 additions & 0 deletions src/views/Testbed.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!--
dev page for experimenting with design and behavior of components. also a
place for seeing all variations at once to check for coherence. not included
in production build of site.
-->
<template>
<!-- status component -->
<AppSection>
<AppGallery>
<AppStatus code="loading" text="Loading some results" />
<AppStatus code="success" text="Action was a success" />
<AppStatus code="warning" text="Be careful" />
<AppStatus code="error" text="There was an error" />
<AppStatus code="paused" text="Action is paused" />
<AppStatus code="unknown" text="Unexpected result" />
</AppGallery>
</AppSection>
<AppSection>
<AppGallery>
<AppStatus code="loading" design="big" text="Loading some results" />
<AppStatus code="success" design="big" text="Action was a success" />
<AppStatus code="warning" design="big" text="Be careful" />
<AppStatus code="error" design="big" text="There was an error" />
<AppStatus code="paused" design="big" text="Action is paused" />
<AppStatus code="unknown" design="big" text="Unexpected result" />
</AppGallery>
</AppSection>
</template>
2 changes: 1 addition & 1 deletion src/views/about/publications.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@
issue: "2:32"
link: "[pubmed](http://www.ncbi.nlm.nih.gov/pubmed/31119199)"

- year: 2019
- year: 2018
list:
- title: "Classification, Ontology, and Precision Medicine (2018)"
authors: "Haendel MA, Chute CG, Robinson PN 2018"
Expand Down
45 changes: 45 additions & 0 deletions tests/unit/AppHeading.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { sleep } from "./../../src/util/debug";
import { flushPromises, mount } from "@vue/test-utils";
import AppHeadings from "./AppHeadings.vue";
import { mountOptions } from "../setup";

const tags = "h1, h2, h3, h4";

test("Chooses heading levels correctly", async () => {
// mount hoc
const wrapper = mount(AppHeadings, mountOptions);

// wait for everything to render
await flushPromises();

// find all heading components
const headings = wrapper.findAll(tags);

// go through each
for (const heading of headings) {
// compare expected tag to actual rendered tag
const received = heading.element.tagName.toLowerCase();
const expected = heading.attributes("data-tag")?.toLowerCase();
expect(received).toBe(expected);
}
});

test("Creates heading links correctly", async () => {
// mount hoc
const wrapper = mount(AppHeadings, mountOptions);

// wait for everything to render
await flushPromises();
await sleep();

// find all heading components
const headings = wrapper.findAll(tags);

// go through each
for (const heading of headings) {
// compare expected link to actual rendered link
const received = heading.attributes("id");
const expected = heading.attributes("data-link");
expect(received).toBe(expected);
}
});
17 changes: 17 additions & 0 deletions tests/unit/AppHeadings.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<template>
<!--
higher-order component (hoc) to test heading auto-levels/links. use data
attributes to indicate expected.
-->
<main>
<AppSection>
<AppHeading data-tag="h1" data-link="abc-def-gih">ABC-def_gih</AppHeading>
</AppSection>
<AppSection>
<AppHeading data-tag="h2" data-link="123-alphabet-street">
123 Alphabet Street
</AppHeading>
<AppHeading data-tag="h3" data-link="aeo">áéó</AppHeading>
</AppSection>
</main>
</template>