fix(webapp): fix mobile invites, settings & global page paddings (#9478)

This commit is contained in:
Ulf Gebhardt 2026-04-02 04:07:49 +02:00 committed by GitHub
parent 192104664d
commit 4c539406bc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
198 changed files with 1486 additions and 211 deletions

View File

@ -41,9 +41,6 @@ reviews:
- "!**/*.min.css"
- "!**/.git/**"
- "!**/storybook-static/**"
# TODO: Temporär - nach Merge des Cypress-Refactoring-PRs entfernen
- "!cypress/support/step_definitions/**"
- "!cypress/e2e/**/*.feature"
# Instruktionen für spezifische Pfade
path_instructions:

View File

@ -149,7 +149,7 @@ jobs:
- name: List feature files
id: list
run: |
FEATURES=$(find cypress/e2e/ -maxdepth 1 -name "*.feature" -printf '%f\n' | sort | jq -R -s -c 'split("\n") | map(select(length > 0))')
FEATURES=$(cd cypress && find e2e/ -name "*.feature" -printf '%P\n' | sort | jq -R -s -c 'split("\n") | map(select(length > 0))')
echo "features=$FEATURES" >> $GITHUB_OUTPUT
fullstack_tests:
@ -249,12 +249,17 @@ jobs:
cd cypress/
node create-cucumber-html-report.js
- name: Full stack tests | if tests failed, compute artifact name
id: artifact-name
if: ${{ failure() && steps.e2e-tests.conclusion == 'failure' }}
run: echo "name=e2e-report-$(echo '${{ matrix.feature }}' | tr '/' '-')" >> $GITHUB_OUTPUT
- name: Full stack tests | if tests failed, upload report
id: e2e-report
if: ${{ failure() && steps.e2e-tests.conclusion == 'failure' }}
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: e2e-report-${{ matrix.feature }}
name: ${{ steps.artifact-name.outputs.name }}
path: /home/runner/work/Ocelot-Social/Ocelot-Social/cypress/reports/cucumber_html_report
e2e_status:

View File

@ -830,15 +830,103 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
// eslint-disable-next-line no-console
console.log('seed', 'invitecodes')
// Peter invited the core users: Jenny, Bob, Huey
await Factory.build(
'inviteCode',
{
code: 'ABCDEF',
},
{
generatedBy: jennyRostock,
},
{ code: 'PETER1', comment: 'For Jenny' },
{ generatedBy: peterLustig },
)
await Factory.build(
'inviteCode',
{ code: 'PETER2', comment: 'For Bob' },
{ generatedBy: peterLustig },
)
await Factory.build(
'inviteCode',
{ code: 'PETER3', comment: 'For Huey' },
{ generatedBy: peterLustig },
)
// Jenny invited Dewey, Louie, Dagobert
await Factory.build(
'inviteCode',
{ code: 'JENNY1', comment: 'For Dewey' },
{ generatedBy: jennyRostock },
)
await Factory.build(
'inviteCode',
{ code: 'JENNY2', comment: 'For Louie' },
{ generatedBy: jennyRostock },
)
await Factory.build(
'inviteCode',
{ code: 'JENNY3', comment: 'For Dagobert' },
{ generatedBy: jennyRostock },
)
// Jenny's shared code (used by additional users)
await Factory.build(
'inviteCode',
{ code: 'ABCDEF', comment: 'Share link' },
{ generatedBy: jennyRostock },
)
// Jenny's unused code (still active)
await Factory.build('inviteCode', { code: 'JNEW01' }, { generatedBy: jennyRostock })
// Jenny's invalidated code (was used once, then deactivated)
await Factory.build(
'inviteCode',
{ code: 'JENNY0', comment: 'Old link', expiresAt: new Date().toISOString() },
{ generatedBy: jennyRostock },
)
// Jenny total: JENNY1, JENNY2, JENNY3, ABCDEF, JNEW01 (5 active) + JENNY0 (1 expired) = 6 codes
// Create REDEEMED and INVITED relationships via Cypher
const inviteSession = database.driver.session()
try {
await inviteSession.writeTransaction((txc) =>
txc.run(`
// Peter's invitations
MATCH (jenny:User {id: 'u3'}), (code1:InviteCode {code: 'PETER1'}), (peter:User {id: 'u1'})
MERGE (jenny)-[:REDEEMED {createdAt: toString(datetime())}]->(code1)
MERGE (peter)-[:INVITED {createdAt: toString(datetime())}]->(jenny)
MERGE (jenny)-[:FOLLOWS {createdAt: toString(datetime())}]->(peter)
MERGE (peter)-[:FOLLOWS {createdAt: toString(datetime())}]->(jenny)
WITH 1 AS dummy
MATCH (bob:User {id: 'u2'}), (code2:InviteCode {code: 'PETER2'}), (peter:User {id: 'u1'})
MERGE (bob)-[:REDEEMED {createdAt: toString(datetime())}]->(code2)
MERGE (peter)-[:INVITED {createdAt: toString(datetime())}]->(bob)
MERGE (bob)-[:FOLLOWS {createdAt: toString(datetime())}]->(peter)
MERGE (peter)-[:FOLLOWS {createdAt: toString(datetime())}]->(bob)
WITH 1 AS dummy
MATCH (huey:User {id: 'u4'}), (code3:InviteCode {code: 'PETER3'}), (peter:User {id: 'u1'})
MERGE (huey)-[:REDEEMED {createdAt: toString(datetime())}]->(code3)
MERGE (peter)-[:INVITED {createdAt: toString(datetime())}]->(huey)
MERGE (huey)-[:FOLLOWS {createdAt: toString(datetime())}]->(peter)
MERGE (peter)-[:FOLLOWS {createdAt: toString(datetime())}]->(huey)
WITH 1 AS dummy
// Jenny's invitations
MATCH (dewey:User {id: 'u5'}), (code4:InviteCode {code: 'JENNY1'}), (jenny:User {id: 'u3'})
MERGE (dewey)-[:REDEEMED {createdAt: toString(datetime())}]->(code4)
MERGE (jenny)-[:INVITED {createdAt: toString(datetime())}]->(dewey)
MERGE (dewey)-[:FOLLOWS {createdAt: toString(datetime())}]->(jenny)
MERGE (jenny)-[:FOLLOWS {createdAt: toString(datetime())}]->(dewey)
WITH 1 AS dummy
MATCH (louie:User {id: 'u6'}), (code5:InviteCode {code: 'JENNY2'}), (jenny:User {id: 'u3'})
MERGE (louie)-[:REDEEMED {createdAt: toString(datetime())}]->(code5)
MERGE (jenny)-[:INVITED {createdAt: toString(datetime())}]->(louie)
MERGE (louie)-[:FOLLOWS {createdAt: toString(datetime())}]->(jenny)
MERGE (jenny)-[:FOLLOWS {createdAt: toString(datetime())}]->(louie)
WITH 1 AS dummy
MATCH (dagobert:User {id: 'u7'}), (code6:InviteCode {code: 'JENNY3'}), (jenny:User {id: 'u3'})
MERGE (dagobert)-[:REDEEMED {createdAt: toString(datetime())}]->(code6)
MERGE (jenny)-[:INVITED {createdAt: toString(datetime())}]->(dagobert)
MERGE (dagobert)-[:FOLLOWS {createdAt: toString(datetime())}]->(jenny)
MERGE (jenny)-[:FOLLOWS {createdAt: toString(datetime())}]->(dagobert)
`),
)
} finally {
await inviteSession.close()
}
authenticatedUser = await louie.toJson()
const mention1 =
@ -1234,6 +1322,32 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
})
}
// Jenny's first 99 additional users all redeemed code ABCDEF
// eslint-disable-next-line no-console
console.log('seed', 'invite redemptions for additional users')
const jennyInviteSession = database.driver.session()
try {
for (let i = 0; i < Math.min(99, additionalUsers.length); i++) {
// eslint-disable-next-line security/detect-object-injection
const userObj = await additionalUsers[i].toJson()
const userId = userObj.id as string
await jennyInviteSession.writeTransaction((txc) =>
txc.run(
`
MATCH (user:User {id: $userId}), (inviteCode:InviteCode {code: 'ABCDEF'}), (jenny:User {id: 'u3'})
MERGE (user)-[:REDEEMED {createdAt: toString(datetime())}]->(inviteCode)
MERGE (jenny)-[:INVITED {createdAt: toString(datetime())}]->(user)
MERGE (user)-[:FOLLOWS {createdAt: toString(datetime())}]->(jenny)
MERGE (jenny)-[:FOLLOWS {createdAt: toString(datetime())}]->(user)
`,
{ userId },
),
)
}
} finally {
await jennyInviteSession.close()
}
// Jenny users
for (let i = 0; i < 30; i++) {
await Factory.build('user', { name: `Jenny${i}` })

View File

@ -0,0 +1,39 @@
Feature: Invite Codes
As a User
I'd like to manage my invite codes
So I can invite friends to the network
Background:
Given the following "users" are in the database:
| email | password | id | name | slug | termsAndConditionsAgreedVersion |
| peterpan@example.org | 123 | id-of-peter-pan | Peter Pan | peter-pan | 0.0.4 |
And I am logged in as "peter-pan"
Scenario: View invite codes page
When I navigate to page "/settings/invites"
Then I am on page "/settings/invites"
And I see the invite code list title with count
Scenario: Generate a new invite code
When I navigate to page "/settings/invites"
Then I am on page "/settings/invites"
When I generate a new invite code
Then I see a toaster with status "success"
And the invite code count has increased
Scenario: Generate a new invite code with comment
When I navigate to page "/settings/invites"
Then I am on page "/settings/invites"
When I generate a new invite code with comment "For my friend"
Then I see a toaster with status "success"
And I see the comment "For my friend" on an invite code
Scenario: Invalidate an invite code
When I navigate to page "/settings/invites"
Then I am on page "/settings/invites"
When I generate a new invite code
Then I see a toaster with status "success"
When I invalidate the first invite code
And I confirm the action in the modal
Then I see a toaster with status "success"
And the invite code count has decreased

View File

@ -8,10 +8,10 @@ CUR_JOB=$(expr $1 - 1)
MAX_JOBS=$2
# Features
FEATURE_LIST=( $(find cypress/e2e/ -maxdepth 1 -name "*.feature") )
FEATURE_LIST=( $(find cypress/e2e/ -name "*.feature") )
# Calculation
MAX_FEATURES=$(find cypress/e2e/ -maxdepth 1 -name "*.feature" -print | wc -l)
MAX_FEATURES=$(find cypress/e2e/ -name "*.feature" -print | wc -l)
# adds overhead features to the first jobs
if [[ $CUR_JOB -lt $(expr ${MAX_FEATURES} % ${MAX_JOBS}) ]]
then

View File

@ -1,6 +1,6 @@
import { defineStep } from '@badeball/cypress-cucumber-preprocessor'
import './../../commands'
import './../../factories'
import './../../../commands'
import './../../../factories'
import 'cypress-network-idle'
defineStep('somebody reported the following posts:', table => {

Some files were not shown because too many files have changed in this diff Show More