# 57 open-source web apps: how many screens, how many end-to-end spec files

14 of the 57 have no end-to-end spec file in their repository, and 32 of the 40 whose screens could be counted have fewer spec files than screens: the median is 0.25 spec files per screen, about one for every 4 screens.

counted 17 Sep 2026 (14 apps, by hand) and 28 Sep 2026 (43 apps, by script) · each app at the commit in its row · open data, CC BY 4.0

[Download CSV](https://featkpr.com/data/open-source-apps-counted-2026-09-28.csv) [Download JSON](https://featkpr.com/data/open-source-apps-counted-2026-09-28.json) [Cite this](https://featkpr.com/library/counted#download) [How we counted](https://featkpr.com/library/counted#method)

## Spec files per screen, app by app

Each row is one app with both counts: its end-to-end spec files divided by its screens, on a log scale. Left of the solid line, the app has fewer spec files than screens.

40 of 57 apps · spec files ÷ screens · log scale, with the apps that have none on the floor

- **Akaunting** none 0 / 121
- **BookStack** none 0 / 93
- **FreshRSS** none 0 / 63
- **Hoppscotch** none 0 / 32
- **Kanboard** none 0 / 102
- **Kimai** none 0 / 48
- **Medusa** none 0 / 186
- **NocoDB** none 0 / 66
- **Outline** none 0 / 32
- **Plane** none 0 / 72
- **Snipe-IT** none 0 / 154
- **Weblate** 0.008 1 / 120
- **Linkwarden** 0.028 1 / 36
- **Mealie** 0.030 2 / 66
- **Twenty** 0.048 9 / 186
- **Wagtail** 0.048 8 / 165
- **Redmine** 0.13 28 / 223
- **Umami** 0.14 8 / 59
- **Supabase Studio** 0.15 29 / 190
- **Paperless-ngx** 0.24 5 / 21
- **PostHog** 0.25 43 / 169
- **Gitea** 0.27 30 / 111
- **InvenTree** 0.30 26 / 87
- **GLPI** 0.34 107 / 315
- **Uptime Kuma** 0.47 7 / 15
- **Mastodon** 0.50 107 / 214
- **Formbricks** 0.63 48 / 76
- **Taiga** 0.65 47 / 72
- **Cal.diy** 0.68 53 / 78
- **Baserow** 0.69 37 / 54
- **Keycloak** 0.86 81 / 94
- **Immich** 0.88 49 / 56
- **Documenso** 1.15 132 / 115
- **Vikunja** 1.22 72 / 59
- **Directus** 1.36 99 / 73
- **Discourse** 1.78 295 / 166
- **OpenProject** 1.94 787 / 406
- **Grafana** 2.37 213 / 90
- **n8n** 4.66 284 / 61
- **Appsmith** 31.8 667 / 21

1 spec file per screen: 32 of 40 apps are left of it the median, 0.25 per screen no end-to-end spec file (11 here) the right column: spec files per screen, then spec files / screens

Not in the picture (17): the apps whose pages are declared in code or generated from records, so there is no page file to count. Their spec files are in the table. Of those, ERPNext, Firefly III, Sylius have no end-to-end spec file either.

## Every app, every count

All 57, with the repository, the commit or tag counted and the date. Sort by any column; the downloads hold the same rows with the rule behind each number.

A zero means the rule found no end-to-end spec file in the repository, not that the project is untested. Many projects test in other ways, and a count of spec files says nothing about a project's quality.

Every app counted, with its screens, API operations, end-to-end spec files, spec files per screen, and the commit or tag counted. Sorted by app name.

| app | licence | screens | API ops | e2e spec files | per screen | counted at (2026) |

|---|---|---|---|---|---|---|

| Akaunting accounting · Laravel | BSL-1.1 | 121 | no spec | 0 | 0 | [github.com/akaunting/akaunting](https://github.com/akaunting/akaunting) [`0c7792b2e` ](https://github.com/akaunting/akaunting/commit/0c7792b2e8cbfe75c6f4f76f78e519770e3601bd) , 27 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Appsmith internal-tool builder · Java · React | Apache-2.0 | 21 | no spec | 667 | 31.8 | [github.com/appsmithorg/appsmith](https://github.com/appsmithorg/appsmith) [`c7e65f8f8` ](https://github.com/appsmithorg/appsmith/commit/c7e65f8f80b39fb33ff4d42fdb91db1dd69a69df) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Baserow no-code database · Django · Nuxt | MIT + premium | 54 | no spec | 37 | 0.69 | [gitlab.com/baserow/baserow](https://gitlab.com/baserow/baserow) default branch · by hand 17 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| BookStack wiki · PHP · Laravel | MIT | 93 | 77 | 0 | 0 | [codeberg.org/bookstack/bookstack](https://codeberg.org/bookstack/bookstack) [`v26.05.5` ](https://codeberg.org/bookstack/bookstack/src/tag/v26.05.5) , 14 Sep · by hand 17 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Cal.diy scheduling · Next.js | MIT | 78 | 121 | 53 | 0.68 | [github.com/calcom/cal.diy](https://github.com/calcom/cal.diy) default branch · by hand 17 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Chatwoot customer support · Rails · Vue | MIT + enterprise | no count | 154 | 3 |  | [github.com/chatwoot/chatwoot](https://github.com/chatwoot/chatwoot) default branch · by hand 17 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Directus data platform · Node · Vue | MSCL-1.0 (source-available) | 73 | 136 | 99 | 1.36 | [github.com/directus/directus](https://github.com/directus/directus) [`1694b1904` ](https://github.com/directus/directus/commit/1694b19048c8523bc90dd1fd11566b748b155ec4) , 25 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Discourse forum · Rails · Ember | GPL-2.0 | 166 | no spec | 295 | 1.78 | [github.com/discourse/discourse](https://github.com/discourse/discourse) [`3b6713ef7` ](https://github.com/discourse/discourse/commit/3b6713ef7768d10cee4f11d033e37f66a1ccad5c) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Documenso document signing · React Router 7 | AGPL-3.0 + ee | 115 | no spec | 132 | 1.15 | [github.com/documenso/documenso](https://github.com/documenso/documenso) default branch · by hand 17 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| ERPNext ERP · Frappe (Python) | GPL-3.0 | no count | no spec | 0 |  | [github.com/frappe/erpnext](https://github.com/frappe/erpnext) [`89f490f72` ](https://github.com/frappe/erpnext/commit/89f490f72edd25d7f0f4fc4c219fd704564d6af7) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Firefly III personal finance · PHP | AGPL-3.0 | no count | no spec | 0 |  | [github.com/firefly-iii/firefly-iii](https://github.com/firefly-iii/firefly-iii) default branch · by hand 17 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Formbricks surveys · Next.js | AGPL-3.0 + ee | 76 | 72 | 48 | 0.63 | [github.com/formbricks/formbricks](https://github.com/formbricks/formbricks) default branch · by hand 17 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| FreshRSS feed reader · PHP | AGPL-3.0 | 63 | no spec | 0 | 0 | [github.com/FreshRSS/FreshRSS](https://github.com/FreshRSS/FreshRSS) [`a8e5e6300` ](https://github.com/FreshRSS/FreshRSS/commit/a8e5e6300b80514d5a14140566c2386a80cf8450) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Ghost publishing · Node · Ember/React | MIT | no count | no spec | 101 |  | [github.com/TryGhost/Ghost](https://github.com/TryGhost/Ghost) [`7c3067680` ](https://github.com/TryGhost/Ghost/commit/7c306768041d7a9e240336af42954cc86deaedfe) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Gitea code hosting · Go templates | MIT | 111 | 537 | 30 | 0.27 | [github.com/go-gitea/gitea](https://github.com/go-gitea/gitea) [`fba8d7eac` ](https://github.com/go-gitea/gitea/commit/fba8d7eaceeed3f8bbc364386d2a35aa672285a2) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| GLPI IT service desk · PHP · Twig | GPL-3.0 | 315 | no spec | 107 | 0.34 | [github.com/glpi-project/glpi](https://github.com/glpi-project/glpi) [`af37be7a7` ](https://github.com/glpi-project/glpi/commit/af37be7a77e6196c49244a2d93e9328003d2c930) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Grafana dashboards · Go · React | AGPL-3.0 | 90 | 314 | 213 | 2.37 | [github.com/grafana/grafana](https://github.com/grafana/grafana) [`5f4490098` ](https://github.com/grafana/grafana/commit/5f4490098b3555e5e9ce6d0a59c07d7463eaeadc) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Hoppscotch API client · Vue · NestJS | MIT | 32 | no spec | 0 | 0 | [github.com/hoppscotch/hoppscotch](https://github.com/hoppscotch/hoppscotch) [`a9ffa29ce` ](https://github.com/hoppscotch/hoppscotch/commit/a9ffa29ce5036ef5be0768db35a8b6bae32e1160) , 23 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Immich photos · NestJS · SvelteKit | AGPL-3.0 | 56 | 276 | 49 | 0.88 | [github.com/immich-app/immich](https://github.com/immich-app/immich) default branch · by hand 17 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| InvenTree inventory · Django · React | MIT | 87 | 670 | 26 | 0.30 | [github.com/inventree/InvenTree](https://github.com/inventree/InvenTree) default branch · by hand 17 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Kanboard kanban · PHP | MIT | 102 | no spec | 0 | 0 | [github.com/kanboard/kanboard](https://github.com/kanboard/kanboard) [`cf53b5459` ](https://github.com/kanboard/kanboard/commit/cf53b54597b67b60140586c09c2fe6132ead013c) , 11 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Keycloak identity and access · Java · React | Apache-2.0 | 94 | no spec | 81 | 0.86 | [github.com/keycloak/keycloak](https://github.com/keycloak/keycloak) [`9f8eb2d23` ](https://github.com/keycloak/keycloak/commit/9f8eb2d23818d11420d80af682e8e9fc6dc4abd8) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Kimai time tracking · Symfony · Twig | AGPL-3.0 | 48 | no spec | 0 | 0 | [github.com/kimai/kimai](https://github.com/kimai/kimai) [`8528bb174` ](https://github.com/kimai/kimai/commit/8528bb174469f0dcc0c4efb5bd18971460d74c78) , 27 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Linkwarden bookmarks · Next.js | AGPL-3.0 | 36 | no spec | 1 | 0.028 | [github.com/linkwarden/linkwarden](https://github.com/linkwarden/linkwarden) [`952ac4540` ](https://github.com/linkwarden/linkwarden/commit/952ac4540657cae3a67c3ca59433899d2fda8374) , 9 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Mastodon social network · Rails · React | AGPL-3.0 | 214 | no spec | 107 | 0.50 | [github.com/mastodon/mastodon](https://github.com/mastodon/mastodon) [`35c345010` ](https://github.com/mastodon/mastodon/commit/35c345010f65b74062bae1d16dcf16924ac6058d) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Mattermost team chat · Go · React | Apache-2.0 + ee | no count | 605 | 996 |  | [github.com/mattermost/mattermost](https://github.com/mattermost/mattermost) [`05553d083` ](https://github.com/mattermost/mattermost/commit/05553d083cd8b9a92ccbcddca6202896ce60c4ae) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Mealie recipes · FastAPI · Nuxt | AGPL-3.0 | 66 | no spec | 2 | 0.030 | [github.com/mealie-recipes/mealie](https://github.com/mealie-recipes/mealie) [`86aec702a` ](https://github.com/mealie-recipes/mealie/commit/86aec702a72f60fa83727b86cb95584bb6e339f0) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Medusa commerce · Node · React | MIT + ee | 186 | 486 | 0 | 0 | [github.com/medusajs/medusa](https://github.com/medusajs/medusa) default branch · by hand 17 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Metabase analytics · Clojure · React | AGPL-3.0 + ee | no count | 637 | 427 |  | [github.com/metabase/metabase](https://github.com/metabase/metabase) [`1a0ff4340` ](https://github.com/metabase/metabase/commit/1a0ff4340be84ec613b09a4613b7d12a44f2403a) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| n8n workflow automation · Node · Vue | Sustainable Use (fair-code) + ee | 61 | 32 | 284 | 4.66 | [github.com/n8n-io/n8n](https://github.com/n8n-io/n8n) [`41dbfd987` ](https://github.com/n8n-io/n8n/commit/41dbfd987b6467b34c572d3b63962213e6befec4) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Nextcloud server file sync and share · PHP · Vue | AGPL-3.0 | no count | 301 | 102 |  | [github.com/nextcloud/server](https://github.com/nextcloud/server) [`c41a9138d` ](https://github.com/nextcloud/server/commit/c41a9138d715c31e9a7684e5ed91ef9c62ccd2b8) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| NocoDB no-code database · Node · Nuxt | Sustainable Use (fair-code) | 66 | 278 | 0 | 0 | [github.com/nocodb/nocodb](https://github.com/nocodb/nocodb) [`8cfa45dcb` ](https://github.com/nocodb/nocodb/commit/8cfa45dcb8ab9241ea06dc255d87bff955de76d9) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Odoo business suite · Python · OWL | LGPL-3.0 | no count | no spec | 525 |  | [github.com/odoo/odoo](https://github.com/odoo/odoo) [`a240a91eb` ](https://github.com/odoo/odoo/commit/a240a91eb01223f59190f4853f748d675f68eaf2) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| OpenProject project management · Rails · Angular | GPL-3.0 | 406 | 331 | 787 | 1.94 | [github.com/opf/openproject](https://github.com/opf/openproject) [`c0146dbdd` ](https://github.com/opf/openproject/commit/c0146dbdd26a2e1be15123cc69e1406746c34ef5) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Outline team wiki · Node · React | BSL-1.1 | 32 | no spec | 0 | 0 | [github.com/outline/outline](https://github.com/outline/outline) [`179d7dd7b` ](https://github.com/outline/outline/commit/179d7dd7be2cb395d45f0151b858e14009cec9d1) , 27 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Paperless-ngx documents · Django · Angular | GPL-3.0 | 21 | no spec | 5 | 0.24 | [github.com/paperless-ngx/paperless-ngx](https://github.com/paperless-ngx/paperless-ngx) [`88000aab4` ](https://github.com/paperless-ngx/paperless-ngx/commit/88000aab45a2b7d321efb9988cd993dd7ee69119) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Penpot design tool · Clojure | MPL-2.0 | no count | no spec | 65 |  | [github.com/penpot/penpot](https://github.com/penpot/penpot) [`f9b8f1ba7` ](https://github.com/penpot/penpot/commit/f9b8f1ba75f04e84a1940ef19d29fc92cb5d6abc) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Plane project tracking · Django · Next.js | AGPL-3.0 | 72 | no spec | 0 | 0 | [github.com/makeplane/plane](https://github.com/makeplane/plane) default branch · by hand 17 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Plausible web analytics · Elixir · React | AGPL-3.0 | no count | no spec | 12 |  | [github.com/plausible/analytics](https://github.com/plausible/analytics) [`ee3a27bb3` ](https://github.com/plausible/analytics/commit/ee3a27bb3d63dd04e51e6e1d811e5d43999e6ac1) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| PostHog product analytics · Django · React | MIT + ee | 169 | no spec | 43 | 0.25 | [github.com/PostHog/posthog](https://github.com/PostHog/posthog) [`cb4522375` ](https://github.com/PostHog/posthog/commit/cb45223750b15b39ba39e333d4c167f440e3920a) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Redmine project tracking · Rails | GPL-2.0+ | 223 | no spec | 28 | 0.13 | [github.com/redmine/redmine](https://github.com/redmine/redmine) [`c9008f4ce` ](https://github.com/redmine/redmine/commit/c9008f4cebbb882d9a16a0b81b18e888744dedc8) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Rocket.Chat team chat · Meteor · React | MIT + ee | no count | no spec | 280 |  | [github.com/RocketChat/Rocket.Chat](https://github.com/RocketChat/Rocket.Chat) [`b149e10ee` ](https://github.com/RocketChat/Rocket.Chat/commit/b149e10ee028e087ef8b25442dc7329f0b038972) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Saleor dashboard commerce admin · React (GraphQL API) | BSD | no count | no spec | 40 |  | [github.com/saleor/saleor-dashboard](https://github.com/saleor/saleor-dashboard) [`8d678ea21` ](https://github.com/saleor/saleor-dashboard/commit/8d678ea217a17187e3bc3dda03df468f3a826617) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Snipe-IT asset management · Laravel | AGPL-3.0 | 154 | no spec | 0 | 0 | [github.com/grokability/snipe-it](https://github.com/grokability/snipe-it) [`d5bf95c02` ](https://github.com/grokability/snipe-it/commit/d5bf95c02a24bbe977b5f21552992a5ef7d3b60b) , 26 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Strapi headless CMS · Node · React | MIT + ee | no count | no spec | 100 |  | [github.com/strapi/strapi](https://github.com/strapi/strapi) [`bba9685b9` ](https://github.com/strapi/strapi/commit/bba9685b9620d09ba87aaeee150f0021335928dd) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Supabase Studio database dashboard · Next.js | Apache-2.0 | 190 | 170 | 29 | 0.15 | [github.com/supabase/supabase](https://github.com/supabase/supabase) [`8e2071247` ](https://github.com/supabase/supabase/commit/8e2071247527a8ba90c588deb0aee6d6ea2bc95f) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Sylius commerce · PHP | MIT | no count | no spec | 0 |  | [github.com/Sylius/Sylius](https://github.com/Sylius/Sylius) default branch · by hand 17 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Taiga agile boards · Django · AngularJS | AGPL-3.0 front · MPL-2.0 back | 72 | no spec | 47 | 0.65 | [github.com/taigaio/taiga-front](https://github.com/taigaio/taiga-front) [`d2da06116` ](https://github.com/taigaio/taiga-front/commit/d2da061168ad6d2526dcc68fdf6117d029c0164c) , 4 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Twenty CRM · NestJS · React | AGPL-3.0 + ee | 186 | no spec | 9 | 0.048 | [github.com/twentyhq/twenty](https://github.com/twentyhq/twenty) default branch · by hand 17 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Umami web analytics · Next.js | MIT | 59 | no spec | 8 | 0.14 | [github.com/umami-software/umami](https://github.com/umami-software/umami) [`ec0ff5038` ](https://github.com/umami-software/umami/commit/ec0ff50388c264ed8ce46f00967e92f7e71476ae) , 16 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Uptime Kuma uptime monitor · Node · Vue | MIT | 15 | no spec | 7 | 0.47 | [github.com/louislam/uptime-kuma](https://github.com/louislam/uptime-kuma) [`b6adc19d0` ](https://github.com/louislam/uptime-kuma/commit/b6adc19d00e4e6700f4b6ffc64a5c4e105e8004c) , 23 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Vikunja tasks · Go · Vue | AGPL-3.0 | 59 | 172 | 72 | 1.22 | [github.com/go-vikunja/vikunja](https://github.com/go-vikunja/vikunja) [`18f3572ed` ](https://github.com/go-vikunja/vikunja/commit/18f3572ed40db4b88d5901c2847efe592c88e9c7) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Wagtail CMS · Django | BSD | 165 | no spec | 8 | 0.048 | [github.com/wagtail/wagtail](https://github.com/wagtail/wagtail) [`e57ccdbc0` ](https://github.com/wagtail/wagtail/commit/e57ccdbc07a0f124e3b88ad69612bafd4131b4cf) , 25 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Weblate translation · Django | GPL-3.0 | 120 | 202 | 1 | 0.008 | [github.com/WeblateOrg/weblate](https://github.com/WeblateOrg/weblate) [`6ff77533c` ](https://github.com/WeblateOrg/weblate/commit/6ff77533c8bb4bb514824cc80496e3ab3d29e261) , 27 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Wiki.js wiki · Node · Vue | AGPL-3.0 | no count | no spec | 1 |  | [github.com/requarks/wiki](https://github.com/requarks/wiki) [`712a3a5bb` ](https://github.com/requarks/wiki/commit/712a3a5bb23b70d7f7325a04b80cc5f20a8f9d9a) , 22 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Zammad helpdesk · Rails · Vue | AGPL-3.0 | no count | no spec | 286 |  | [github.com/zammad/zammad](https://github.com/zammad/zammad) [`619ef87bb` ](https://github.com/zammad/zammad/commit/619ef87bb2173ee91640ff58b1eed2edcec5fabb) , 28 Sep · script 28 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

| Zulip team chat · Django · Tornado | Apache-2.0 | no count | no spec | 20 |  | [github.com/zulip/zulip](https://github.com/zulip/zulip) default branch · by hand 17 Sep · [correct this row](https://featkpr.com/about/how-we-write#corrections) |

If a row is wrong, write to hello@featkpr.com with the app and the column; we correct it and date the fix on this page. [How corrections work](https://featkpr.com/about/how-we-write#corrections) .

"no count": the screens cannot be counted from the files, or no API spec is committed; hover for the reason, and the downloads carry it. "by hand": report T2, 17 Sep 2026. "script": tools/library_count.py, 28 Sep 2026.

## How we counted

The protocol of our research report T2 (17 Sep 2026), made mechanical on 28 Sep 2026 in one script. Every number is a count of files in the repository, at the commit shown, with the rule that produced it.

**A screen**

a page a person can land on: one page file or one route declaration, never a component. In file-routed front ends (Next.js, SvelteKit, Nuxt, React Router route modules, a Vue app's views), page files minus layouts, API routes and _app/_document. Where the router is code (React Router, Vue Router, Angular, Ember, AngularJS), the route declarations in the router file the rule names. In server-rendered apps (Rails, Django, Laravel, Twig, Go templates, plain PHP), the templates that render a whole page: ones that extend a layout, or a Rails view that is not a partial, a layout or a mail.

**No screen count**

an app whose pages cannot be counted either way from its files (routes spread across the code, or screens generated from records) gets none, with the reason, rather than a guess.

**An API operation**

a (path, method) pair in the OpenAPI or Swagger spec committed to the repository, following a spec split into files through its $refs. No committed spec (GraphQL, RPC, a spec generated only at runtime or kept in another repository): no count.

**An end-to-end spec file**

a file of the suite the project runs against the running app from outside, through a browser (Playwright, Cypress, Puppeteer, Selenium, Protractor, Capybara system specs, Odoo tours) or over HTTP, in the directory the project names for it. Unit, component and in-process HTTP tests are not counted.

**Spec files are not tests.** One spec file can hold one test or fifty. We count files because a file is what the rule can see without running anything.

**Screens are not features.** A screen is a page file. One screen can carry many features, and one feature can span many screens.

Two counts: report T2 counted 14 apps by hand on 17 Sep 2026 (BookStack at its v26.05.5 tag, the others at their default branch that day, with no commit recorded). On 28 Sep 2026 the script counted 43 more at each repository's default branch, and recounted 4 of T2's apps to check the rules against T2's figures.

### Where both counts exist

T2's hand count (17 Sep) beside the script's (28 Sep). The table and the picture use T2's; the downloads carry both.

| app | count | T2, 17 Sep 2026 | script, 28 Sep 2026 |

|---|---|---|---|

| Documenso `a1d4bec14` | screens | 115 | 112 differs |

| API operations | no count | no count |  |

| e2e spec files | 132 | 135 differs |  |

| Formbricks `43db6ad83` | screens | 76 | 78 differs |

| API operations | 72 | 72 |  |

| e2e spec files | 48 | 49 differs |  |

| Immich `aa0233784` | screens | 56 | 56 |

| API operations | 276 | 276 |  |

| e2e spec files | 49 | 49 |  |

| InvenTree `c2b7f71f2` | screens | 87 | 87 |

| API operations | 670 | no count differs |  |

| e2e spec files | 26 | 26 |  |

InvenTree's API count differs because its spec is kept in another repository (inventree/schema): T2 read it there, and the script reads only the repository it counts.

## What this does not show

- **Not a sample of all open-source apps.** The apps were picked as candidates for featkpr to map, plus well-known self-hosted apps across stacks. Nothing here says what share of all projects have end-to-end suites.
- **Not a measure of quality.** Fewer spec files than screens does not mean a screen is untested: unit and integration tests are not counted, and one spec file can cover many screens.
- **Rules differ by stack.** A screen in a Rails app (a template) and in a React app (a route declaration) are counted by different rules, so compare apps within a stack with more care than across stacks.
- **One moment in time.** Each count is at one commit. Repositories move every day; run the rule again and the number may differ.
- **Rules, not a reading of every file.** Each number is what its rule matched, and the 4 recounted apps are checked against T2's hand counts. A rule can still count a file it should not, or miss one.

## How to count it again

Every row names the repository, the commit and the rule, so any one number can be checked with a clone and a file listing.

- Clone the repository and check out the commit in the row.
- List the files: git ls-tree -r --name-only HEAD.
- Apply the row's rule: the files whose path matches the pattern, minus the exclusion, or the files whose text matches it. The count is the number of files (or of route declarations, where the rule says occurrences).

The script that did it, tools/library_count.py (Python, no dependencies beyond an optional YAML reader), shallow-clones each repository with no blobs, fetches only the files a rule must read and prints one JSON record per app. Its output of 28 Sep 2026 is the receipt the site reads. Run today, it counts today's default branch, so the numbers move with the repositories.

[The data are also on GitHub: github.com/featkpr/open-source-apps-counted (CC BY 4.0). The counting script follows there.](https://github.com/featkpr/open-source-apps-counted)

receipt: research/reports/library-count-2026-09-28.json · 47 records, one per repository counted on 28 Sep 2026

## A neighbour dataset: E2EGit

The closest published dataset we know of, and how this one differs.

University of Naples Federico II and Vrije Universiteit Brussel · 2025 IEEE/ACM 22nd International Conference on Mining Software Repositories (MSR), pp. 836-840 · read 28 Sep 2026

[E2EGit: A Dataset of End-to-End Web Tests in Open Source Projects](https://doi.org/10.1109/MSR66628.2025.00121) (Sergio Di Meglio, Luigi Libero Lucio Starace, Valeria Pontillo, Ruben Opdebeeck, Coen De Roover, Sergio Di Martino) publishes a dataset of GitHub repositories written in Java, JavaScript, TypeScript or Python that depend on a web framework. It finds Selenium, Playwright, Puppeteer and Cypress tests (and JMeter and Locust performance tests) and counts test cases per file.

| aspect | E2EGit | this count |

|---|---|---|

| What is counted | test cases, inside each test file | end-to-end spec files, not the tests inside them |

| Which projects | 5,563 web repositories (at least 2,000 commits, 10 contributors and 100 stars, not a fork); the 472 with web GUI tests are listed | 57 apps, chosen one by one; the 14 with no end-to-end spec file are in the data |

| The app's size | commits, contributors, lines of code and stars, not its pages | screens, and API operations where a spec is committed |

| What it found | 43,670 web GUI test cases in 472 repositories, and 271 performance tests in 84 | 6,233 end-to-end spec files in 43 apps |

| When | mined May 2024; published 26 Nov 2024 | counted 17 Sep 2026 and 28 Sep 2026 |

| Licence | CC BY 4.0, on Zenodo | CC BY 4.0, on this page |

Paper: doi 10.1109/MSR66628.2025.00121 ([the authors' PDF](https://soft.vub.ac.be/Publications/2025/vub-tr-soft-25-04.pdf) ). Data: [Zenodo, doi 10.5281/zenodo.14221860](https://zenodo.org/records/14221860) , CC BY 4.0. Every E2EGit figure above is from the paper, read 28 Sep 2026.

## Download and cite

The same rows as the table, with the rule behind every number, generated from the site's data when the site is built.

- [**open-source-apps-counted-2026-09-28.csv**](https://featkpr.com/data/open-source-apps-counted-2026-09-28.csv) UTF-8, one row per app. The first lines start with # and name the licence, the source and the dates: skip them as comments (pandas: comment="#").
- [**open-source-apps-counted-2026-09-28.json**](https://featkpr.com/data/open-source-apps-counted-2026-09-28.json) The rows, a dictionary of every column, the summary figures on this page and the provenance.

Licence: [Creative Commons Attribution 4.0 International (CC BY 4.0)](https://creativecommons.org/licenses/by/4.0/) . Use it for anything, including commercially; name featkpr as the source and link to this page.

### Cite this

`featkpr, 57 open-source web apps counted, 28 Sep 2026, CC BY 4.0, https://featkpr.com/library/counted`

BibTeX

```

@misc{featkpr_counted_20260928,
  author       = {{featkpr}},
  title        = {57 open-source web apps counted: screens, API operations and end-to-end spec files},
  year         = {2026},
  month        = {sep},
  howpublished = {\url{https://featkpr.com/library/counted}},
  note         = {Dataset, CC BY 4.0. Counted 17 Sep 2026 and 28 Sep 2026}
} 

```

## See featkpr map an app

We counted these apps to choose which ones featkpr maps first. featkpr maps a web app's features, the flows people take through them and the goals they reach, and tests sit on top of that map. The counts are published as they are, so anyone can check them, reuse them or count more.

[Ask for a private demo](https://featkpr.com/demo)

---

The page this twin stands for: https://featkpr.com/library/counted. Every page on this site has a `.md` twin, and answers `Accept: text/markdown`.
