Merge pull request #31742 from overleaf/ii-project-sharing-join-project

[web] Join project page redesign

GitOrigin-RevId: d182ec4fb744f384f824c9e63b534da02a9f8e99
This commit is contained in:
ilkin-overleaf
2026-03-06 09:17:16 +00:00
committed by Copybot
parent d5a65e906f
commit 6539e26107
18 changed files with 371 additions and 106 deletions
@@ -1,4 +1,5 @@
import TokenAccessPage from '@/features/token-access/components/token-access-root'
import { SplitTestProvider } from '@/shared/context/split-test-context'
import { location } from '@/shared/components/location'
describe('<TokenAccessPage/>', function () {
@@ -9,6 +10,9 @@ describe('<TokenAccessPage/>', function () {
cy.window().then(win => {
win.metaAttributesCache.set('ol-postUrl', url)
win.metaAttributesCache.set('ol-user', { email: 'test@example.com' })
win.metaAttributesCache.set('ol-splitTestVariants', {
'sharing-updates': 'enabled',
})
})
})
@@ -22,15 +26,21 @@ describe('<TokenAccessPage/>', function () {
}
).as('grantRequest')
cy.mount(<TokenAccessPage />)
cy.mount(
<SplitTestProvider>
<TokenAccessPage />
</SplitTestProvider>
)
cy.wait('@grantRequest').then(interception => {
expect(interception.request.body.confirmedByUser).to.be.false
})
cy.get('.link-sharing-invite-header').should(
'have.text',
['You’re joining', 'Test Project', 'as test@example.com'].join('')
cy.findByRole('heading', {
name: /you’re joining Test Project as test@example.com/i,
})
cy.findByText(
/your name and email address will be visible to project editors/i
)
cy.intercept(
@@ -44,7 +54,7 @@ describe('<TokenAccessPage/>', function () {
cy.stub(location, 'replace').as('replaceLocation')
cy.findByRole('button', { name: 'OK, join project' }).click()
cy.findByRole('button', { name: /join project/i }).click()
cy.wait('@confirmedGrantRequest').then(interception => {
expect(interception.request.body.confirmedByUser).to.be.true
@@ -61,7 +71,11 @@ describe('<TokenAccessPage/>', function () {
'grantRequest'
)
cy.mount(<TokenAccessPage />)
cy.mount(
<SplitTestProvider>
<TokenAccessPage />
</SplitTestProvider>
)
cy.wait('@grantRequest')
@@ -83,7 +97,11 @@ describe('<TokenAccessPage/>', function () {
cy.stub(location, 'replace').as('replaceLocation')
cy.mount(<TokenAccessPage />)
cy.mount(
<SplitTestProvider>
<TokenAccessPage />
</SplitTestProvider>
)
cy.wait('@grantRequest')
@@ -102,7 +120,11 @@ describe('<TokenAccessPage/>', function () {
cy.stub(location, 'replace').as('replaceLocation')
cy.mount(<TokenAccessPage />)
cy.mount(
<SplitTestProvider>
<TokenAccessPage />
</SplitTestProvider>
)
cy.wait('@grantRequest')
@@ -125,7 +147,11 @@ describe('<TokenAccessPage/>', function () {
cy.stub(location, 'replace').as('replaceLocation')
cy.mount(<TokenAccessPage />)
cy.mount(
<SplitTestProvider>
<TokenAccessPage />
</SplitTestProvider>
)
cy.wait('@grantRequest')
@@ -149,7 +175,11 @@ describe('<TokenAccessPage/>', function () {
cy.stub(location, 'replace').as('replaceLocation')
cy.mount(<TokenAccessPage />)
cy.mount(
<SplitTestProvider>
<TokenAccessPage />
</SplitTestProvider>
)
cy.wait('@grantRequest')
@@ -763,59 +763,105 @@ describe('CollaboratorsInviteController', function () {
})
describe('when the token is valid', function () {
beforeEach(async function (ctx) {
await new Promise(resolve => {
ctx.res.callback = () => resolve()
ctx.CollaboratorsInviteController.viewInvite(
ctx.req,
ctx.res,
ctx.next
describe('when the sharing-updates variant is "enabled"', function () {
beforeEach(async function (ctx) {
ctx.SplitTestHandler.promises.getAssignment.resolves({
variant: 'enabled',
})
await new Promise(resolve => {
ctx.res.callback = () => resolve()
ctx.CollaboratorsInviteController.viewInvite(
ctx.req,
ctx.res,
ctx.next
)
})
})
it('should render the new view template', function (ctx) {
expect(ctx.res.render).toHaveBeenCalledTimes(1)
expect(ctx.res.render).toHaveBeenCalledWith(
'project/invite/show',
expect.anything()
)
})
it('should not call next', function (ctx) {
ctx.next.callCount.should.equal(0)
})
})
it('should render the view template', function (ctx) {
expect(ctx.res.render).toHaveBeenCalledTimes(1)
expect(ctx.res.render).toHaveBeenCalledWith(
'project/invite/show',
expect.anything()
)
describe('when the sharing-updates variant is "default"', function () {
beforeEach(async function (ctx) {
ctx.SplitTestHandler.promises.getAssignment.resolves({
variant: 'default',
})
await new Promise(resolve => {
ctx.res.callback = () => resolve()
ctx.CollaboratorsInviteController.viewInvite(
ctx.req,
ctx.res,
ctx.next
)
})
})
it('should render the legacy view template', function (ctx) {
expect(ctx.res.render).toHaveBeenCalledTimes(1)
expect(ctx.res.render).toHaveBeenCalledWith(
'project/invite/show-legacy',
expect.anything()
)
})
it('should not call next', function (ctx) {
ctx.next.callCount.should.equal(0)
})
})
it('should not call next', function (ctx) {
ctx.next.callCount.should.equal(0)
})
describe('common behaviour', function () {
beforeEach(async function (ctx) {
await new Promise(resolve => {
ctx.res.callback = () => resolve()
ctx.CollaboratorsInviteController.viewInvite(
ctx.req,
ctx.res,
ctx.next
)
})
})
it('should call CollaboratorsGetter.isUserInvitedMemberOfProject', function (ctx) {
ctx.CollaboratorsGetter.promises.isUserInvitedMemberOfProject.callCount.should.equal(
1
)
ctx.CollaboratorsGetter.promises.isUserInvitedMemberOfProject
.calledWith(ctx.currentUser._id, ctx.projectId)
.should.equal(true)
})
it('should call CollaboratorsGetter.isUserInvitedMemberOfProject', function (ctx) {
ctx.CollaboratorsGetter.promises.isUserInvitedMemberOfProject.callCount.should.equal(
1
)
ctx.CollaboratorsGetter.promises.isUserInvitedMemberOfProject
.calledWith(ctx.currentUser._id, ctx.projectId)
.should.equal(true)
})
it('should call getInviteByToken', function (ctx) {
ctx.CollaboratorsInviteGetter.promises.getInviteByToken.callCount.should.equal(
1
)
ctx.CollaboratorsInviteGetter.promises.getInviteByToken
.calledWith(ctx.fakeProject._id, ctx.invite.token)
.should.equal(true)
})
it('should call getInviteByToken', function (ctx) {
ctx.CollaboratorsInviteGetter.promises.getInviteByToken.callCount.should.equal(
1
)
ctx.CollaboratorsInviteGetter.promises.getInviteByToken
.calledWith(ctx.fakeProject._id, ctx.invite.token)
.should.equal(true)
})
it('should call User.getUser', function (ctx) {
ctx.UserGetter.promises.getUser.callCount.should.equal(1)
ctx.UserGetter.promises.getUser
.calledWith({ _id: ctx.fakeProject.owner_ref })
.should.equal(true)
})
it('should call User.getUser', function (ctx) {
ctx.UserGetter.promises.getUser.callCount.should.equal(1)
ctx.UserGetter.promises.getUser
.calledWith({ _id: ctx.fakeProject.owner_ref })
.should.equal(true)
})
it('should call ProjectGetter.getProject', function (ctx) {
ctx.ProjectGetter.promises.getProject.callCount.should.equal(1)
ctx.ProjectGetter.promises.getProject
.calledWith(ctx.projectId)
.should.equal(true)
it('should call ProjectGetter.getProject', function (ctx) {
ctx.ProjectGetter.promises.getProject.callCount.should.equal(1)
ctx.ProjectGetter.promises.getProject
.calledWith(ctx.projectId)
.should.equal(true)
})
})
})