", "": ""} {
if got, err := wrapperMarkup(w); err != nil || got != want {
t.Errorf("wrapperMarkup(%q) = %q, %v; want %q", w, got, err, want)
}
}
if _, err := wrapperMarkup("card"); err == nil {
t.Error("wrapperMarkup accepted a wrapper the manifest does not have")
}
}
// TestABodyWithoutItsWrapperFailsTheRender: a seeded document whose
// body has lost its wrapper fails the render naming the state, rather
// than being shown with a wrapper line over markup that has none.
func TestABodyWithoutItsWrapperFailsTheRender(t *testing.T) {
const file = "examples/field-text/bare.html"
raw, err := fs.ReadFile(fiesta.FS(), file)
if err != nil {
t.Fatal(err)
}
stripped := strings.Replace(string(raw), "
", "", 1)
stripped = strings.Replace(stripped, "", "", 1)
if stripped == string(raw) {
t.Fatal("the control did not change the document")
}
_, err = Render(overlay{fiesta.FS(), map[string][]byte{file: []byte(stripped)}}, Options{})
if err == nil {
t.Fatal("a body without its wrapper rendered")
}
if !strings.Contains(err.Error(), "field-text/bare") {
t.Errorf("the error does not name the state: %v", err)
}
}
// TestAGroupedPartialNeedsNoWrapper: the grouped examples are the three
// Rastrillo groups, each in the manifest and none wrapped: the grouped
// panels carry no wrapper line, so a wrapped one would be copied
// without its container.
func TestAGroupedPartialNeedsNoWrapper(t *testing.T) {
if len(grouped) == 0 {
t.Fatal("no example is grouped, so this checked nothing")
}
m := manifest(t)
for _, name := range []string{"status-pill", "badge", "meter"} {
if !grouped[name] {
t.Errorf("%s is not grouped", name)
}
}
for name := range grouped {
e, ok := m.Entry(name)
if !ok {
t.Errorf("%s is grouped and not in the manifest", name)
continue
}
if w, err := wrapperMarkup(e.Wrapper); err != nil || w != "" {
t.Errorf("%s is grouped and wrapped in %s; the grouped panels would drop the line saying so", name, w)
}
if len(e.States) < 2 {
t.Errorf("%s is grouped with %d state; a group is a row of several", name, len(e.States))
}
}
}
// TestAGroupedNoteNamesItsStateApart: under a grouped widget, every
// state has a block of its own naming the state in an element of its
// own, with the note, where there is one, as a paragraph after it and
// nothing written between the two: a joiner would be copy no review
// saw, and an ASCII colon is wrong punctuation in ja, zh-Hans and yue.
func TestAGroupedNoteNamesItsStateApart(t *testing.T) {
files := render(t, "")
p := loadedProse(t)
s := newTestSite(t, fiesta.FS(), "")
m := s.m
theme := fiesta.ThemeNames()[0]
notes, blocks := 0, 0
for _, locale := range Locales {
for name := range grouped {
e, ok := m.Entry(name)
if !ok {
t.Fatalf("no %s example", name)
}
page := examplePage(t, files, theme, locale, name)
for _, st := range e.States {
blocks++
// The label and the note in the page's language, read
// through the lookups the page renders them with.
label := s.label(locale, e, st)
open := `
` + template.HTMLEscapeString(label) + "\n"
if !strings.Contains(page, open) {
t.Errorf("%s/%s %s: no block names the %s state apart", theme, locale, name, st.ID)
continue
}
note := s.proseIn(locale, "examples."+name+".states."+st.ID, p.Examples[name].States[st.ID])
if note == "" {
if strings.Contains(page, open+`
`) {
t.Errorf("%s/%s %s/%s has a note and the prose has none", theme, locale, name, st.ID)
}
continue
}
notes++
if !strings.Contains(page, open+`
`+template.HTMLEscapeString(note)+"
\n
") {
t.Errorf("%s/%s %s/%s: the note does not follow its state on a line of its own", theme, locale, name, st.ID)
}
if joined := template.HTMLEscapeString(label + ": " + note); strings.Contains(page, joined) {
t.Errorf("%s/%s %s/%s: the note is joined to its state as %q", theme, locale, name, st.ID, joined)
}
}
}
}
if notes == 0 || blocks == 0 {
t.Fatalf("%d grouped notes and %d state blocks checked; the walk read nothing", notes, blocks)
}
}
// TestEveryPreviewIsAFileOneFrameNames: every frame document in the
// tree is the src of exactly one frame on one page, except the
// per-state documents of a grouped example, which no frame names (the
// accessibility gate scans them one state at a time) and which are
// counted here. The root index is day/en/index.html again and is not
// walked twice.
func TestEveryPreviewIsAFileOneFrameNames(t *testing.T) {
files := render(t, "")
named := map[string]int{}
frames := 0
for name, body := range files {
if !strings.HasSuffix(name, ".html") || isFrame(name) || name == "index.html" {
continue
}
attrsOf(t, body, func(tag string, attrs map[string]string) {
if tag == "iframe" && attrs["class"] == "ds-view__frame" {
frames++
named[strings.TrimPrefix(attrs["src"], "/")]++
}
})
}
if len(grouped) == 0 {
t.Fatal("no example is grouped, so the exception below is never exercised")
}
previews, unframed := 0, 0
for name := range files {
if !isFrame(name) {
continue
}
previews++
parts := strings.Split(name, "/")
example, state := parts[len(parts)-2], strings.TrimSuffix(parts[len(parts)-1], ".html")
want := 1
if grouped[example] && state != "row" {
want, unframed = 0, unframed+1
}
if n := named[name]; n != want {
t.Errorf("%s is the src of %d frames, want %d", name, n, want)
}
}
if frames == 0 || previews == 0 || unframed == 0 {
t.Fatalf("%d frames, %d frame documents, %d of them a grouped state's; this gate is checking nothing", frames, previews, unframed)
}
t.Logf("%d frames name %d documents; %d grouped state documents are scanned and not framed", frames, previews-unframed, unframed)
}
// TestTheTextOnScreenIsTheTextCopied: every HTML panel's blocks, with
// the highlighting removed, are exactly the source they stand for, in
// order: the formatted body without its wrapper for a component, the
// whole formatted document for a layout, and one block per state for
// a grouped example. In English and in Arabic, where the source is the
// sample in the page's language: the body through localMarkup, the
// layout's document with its body and title in Arabic and its
// saying so, and the money sample the money table's Arabic markup.
func TestTheTextOnScreenIsTheTextCopied(t *testing.T) {
files := render(t, "")
m := manifest(t)
s := newTestSite(t, fiesta.FS(), "")
theme := fiesta.ThemeNames()[0]
checked := 0
for _, locale := range []string{"en", "ar"} {
for _, e := range m.Examples {
var want []string
for _, st := range e.States {
var src string
if e.Document {
doc, err := example.Document(fiesta.FS(), e.Name, st.ID)
if err != nil {
t.Fatal(err)
}
if doc, err = s.localDocument(locale, e, st, doc); err != nil {
t.Fatal(err)
}
if src, err = localHTML(doc, locale); err != nil {
t.Fatal(err)
}
} else {
markup, err := example.Markup(fiesta.FS(), e.Name, st.ID)
if err != nil {
t.Fatal(err)
}
markup = localMarkup(locale, e.Name, markup)
if e.Name == moneyExample && st.ID == e.Default {
markup, _ = s.moneyBody(locale)
}
if src, err = unwrap(markup, e.Wrapper); err != nil {
t.Fatalf("%s/%s: %v", e.Name, st.ID, err)
}
}
want = append(want, codeview.Format(src))
}
// The control, independent of unwrap: a wrapped example's
// expected block does not open with its wrapper.
for i, w := range want {
if e.Wrapper == "" {
continue
}
for _, open := range wrapperOpenings {
if strings.HasPrefix(strings.TrimSpace(w), open) {
t.Errorf("%s/%s block %d: the expected source still opens with %s; unwrap left the wrapper in", locale, e.Name, i, open)
}
}
}
got := sourceTexts(examplePage(t, files, theme, locale, e.Name))
if len(got) != len(want) {
t.Errorf("%s/%s: %d source blocks on the page, want %d", locale, e.Name, len(got), len(want))
continue
}
for i := range want {
checked++
if got[i] != want[i] {
t.Errorf("%s/%s block %d: on screen\n%s\nwant\n%s", locale, e.Name, i, got[i], want[i])
}
}
}
}
if checked == 0 {
t.Fatal("no block was compared")
}
}
// TestEveryCodeBlockOffersTheCopyButton: no block in the tree refuses
// the Copy button (no Fiesta example is an illustration), and on day/en
// every block is a copyable block inside an HTML panel, one per state.
func TestEveryCodeBlockOffersTheCopyButton(t *testing.T) {
files := render(t, "")
m := manifest(t)
theme := fiesta.ThemeNames()[0]
for name, body := range files {
if strings.HasSuffix(name, ".html") && strings.Contains(string(body), "data-ds-nocopy") {
t.Errorf("%s carries a block that refuses the Copy button", name)
}
}
const block = `
`
blocks, inPanels, states := 0, 0, 0
for _, e := range m.Examples {
page := examplePage(t, files, theme, "en", e.Name)
states += len(e.States)
blocks += strings.Count(page, block)
for _, w := range widgetsOf(page) {
inPanels += strings.Count(panelOf(w), block)
}
}
if blocks == 0 || blocks != states || inPanels != blocks {
t.Errorf("day/en has %d copyable blocks, %d of them in HTML panels, over %d states; want one per state, every one in a panel", blocks, inPanels, states)
}
}
// TestEveryFrameTitleIsUniqueOnThePage: a frame's title is an
// accessible name, unique on its page, and never the empty label's
// bare "name: ": a state with no label takes the example's name.
func TestEveryFrameTitleIsUniqueOnThePage(t *testing.T) {
files := render(t, "")
titleAttr := regexp.MustCompile(`