cat / 012
clone

a spreadsheet for the terminal: lotus 1-2-3 looks, google sheets keys and formulas, one go binary

cat/module-path
012 / e2e / pivot_test.go
pivot_test.go 4.1K
1package e2e23import (4 "fmt"5 "strings"6 "testing"7)89// inventoryQty sums the inventory fixture's quantities by category.10func inventoryQty() (fasteners, hardware int) {11 for i := range 40 {12 qty := (i*37)%90 + 513 if k := i % 8; k == 3 || k == 4 || k == 6 {14 hardware += qty15 } else {16 fasteners += qty17 }18 }19 return fasteners, hardware20}2122// pivotByCategory creates a pivot of the inventory with Category in Rows23// and SUM of Qty in Values, leaving the editor open on the value.24func pivotByCategory(s *session) {25 inventory(s)26 s.keys("<ctrl+k>", "pivot table", "<enter>")27 s.waitFor("PIVOT")28 s.waitFor("Data Sheet1!A1:F41")29 s.keys("<space>", "categ", "<enter>")30 s.waitFor(" Category")31 s.keys("<down>", "<down>", "<space>", "qty", "<enter>")32 s.waitFor("‹ SUM ›")33}3435func TestPivotTable(t *testing.T) {36 t.Parallel()37 dir := t.TempDir()38 s := start(t, dir)39 pivotByCategory(s)40 s.keys("<enter>")41 s.waitFor("READY")42 fasteners, hardware := inventoryQty()43 s.eventually("pivot results", func() bool {44 return strings.HasPrefix(s.line(gridRow1), " 1 Category") &&45 strings.Contains(s.line(gridRow1+1), fmt.Sprint(fasteners)) &&46 strings.Contains(s.line(gridRow1+3), fmt.Sprint(fasteners+hardware))47 })48 if !strings.Contains(s.line(int(s.rows)-1), "Pivot Table 1") {49 t.Errorf("no tab for the pivot: %q", s.line(int(s.rows)-1))50 }5152 // Its results can't be edited.53 s.keys("<down>", "<right>", "7")54 s.waitFor("Pivot table results can't be edited")5556 // It follows its source: Bolts 1's quantity goes up by 1000.57 s.keys("<ctrl+pgup>", "<f5>", "D2", "<enter>", "1005", "<enter>", "<ctrl+pgdown>")58 s.eventually("recomputed", func() bool {59 return strings.Contains(s.line(gridRow1+1), fmt.Sprint(fasteners+1000))60 })6162 // Saved as its definition, and computed again on opening.63 s.keys("<ctrl+s>", "stock", "<enter>")64 s.eventually("saved", func() bool { return s.title() == "012 - stock.012" })65 s.keys("<ctrl+q>")66 s.waitExit()67 r := start(t, dir, "stock.012")68 r.keys("<ctrl+pgdown>")69 r.eventually("pivot after reopening", func() bool {70 return strings.Contains(r.line(gridRow1+1), fmt.Sprint(fasteners+1000)) && strings.Contains(r.screen(), "Grand Total")71 })7273 // Esc in the editor undoes its changes; undo takes the edit back.74 r.keys("<ctrl+k>", "edit pivot", "<enter>")75 r.waitFor("PIVOT")76 r.keys("<down>", "<delete>")77 r.eventually("category removed", func() bool { return !strings.Contains(r.line(gridRow1), "Category") })78 r.keys("<esc>")79 r.waitFor("READY")80 r.eventually("category back", func() bool { return strings.HasPrefix(r.line(gridRow1), " 1 Category") })81}8283func TestFrequencyTable(t *testing.T) {84 t.Parallel()85 s := start(t, "")86 inventory(s)87 s.keys("<right>", "<down>", "<alt+shift+f>")88 s.waitFor("Counted Category: 2 distinct values")89 fasteners := 090 for i := range 40 {91 if k := i % 8; k != 3 && k != 4 && k != 6 {92 fasteners++93 }94 }95 s.eventually("counts", func() bool {96 return strings.HasPrefix(s.line(gridRow1), " 1 Category") &&97 strings.Contains(s.line(gridRow1+1), "Fasteners") && strings.Contains(s.line(gridRow1+1), fmt.Sprint(fasteners)) &&98 strings.Contains(s.line(gridRow1+3), "100.00%")99 })100 s.keys("<ctrl+z>")101 s.eventually("undone", func() bool { return !strings.Contains(s.line(int(s.rows)-1), "Frequency of") })102}103104func TestPivotRenameAndColumnSubtotals(t *testing.T) {105 t.Parallel()106 s := start(t, "")107 pivotByCategory(s)108 // R renames the value on the context line.109 s.keys("r")110 s.waitFor("Value name: SUM of Qty")111 s.keys("Units", "<enter>")112 s.waitFor("PIVOT")113 s.eventually("renamed header", func() bool { return strings.Contains(s.line(gridRow1), "Units") })114 // Category moves from Rows to Columns, after Reorder: a subtotal115 // column follows each Reorder value.116 s.keys("<up>", "<up>", "<up>", "<delete>")117 s.eventually("category removed", func() bool { return !strings.Contains(s.line(gridRow1), "Category") })118 s.keys("<space>", "reord", "<enter>")119 s.waitFor(" Reorder")120 s.keys("a", "categ", "<enter>")121 s.waitFor(" Category")122 s.keys("<enter>")123 s.waitFor("READY")124 s.eventually("subtotal columns", func() bool {125 return strings.Contains(s.line(gridRow1), "no Total") && strings.Contains(s.line(gridRow1), "yes Total")126 })127}