From 7d339936dec9d8914b6cee0cec569e3d67bb5e90 Mon Sep 17 00:00:00 2001 From: Laura Beatris <48022589+LauraBeatris@users.noreply.github.com> Date: Wed, 1 Oct 2025 19:51:48 -0300 Subject: [PATCH 1/9] Update FAPI resource --- .../clerk-js/src/core/resources/OrganizationSettings.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/clerk-js/src/core/resources/OrganizationSettings.ts b/packages/clerk-js/src/core/resources/OrganizationSettings.ts index 09edfd6b58b..2281deb9ba4 100644 --- a/packages/clerk-js/src/core/resources/OrganizationSettings.ts +++ b/packages/clerk-js/src/core/resources/OrganizationSettings.ts @@ -18,6 +18,11 @@ export class OrganizationSettings extends BaseResource implements OrganizationSe enrollmentModes: [], defaultRole: null, }; + slugs: { + disabled: boolean; + } = { + disabled: false, + }; enabled: boolean = false; maxAllowedMemberships: number = 1; forceOrganizationSelection!: boolean; @@ -42,6 +47,10 @@ export class OrganizationSettings extends BaseResource implements OrganizationSe this.domains.defaultRole = this.withDefault(data.domains.default_role, this.domains.defaultRole); } + if (data.slugs) { + this.slugs.disabled = this.withDefault(data.slugs.disabled, this.slugs.disabled); + } + this.enabled = this.withDefault(data.enabled, this.enabled); this.maxAllowedMemberships = this.withDefault(data.max_allowed_memberships, this.maxAllowedMemberships); this.forceOrganizationSelection = this.withDefault( From 89c8d3240774168bc0594ea83d6a92454f66f97d Mon Sep 17 00:00:00 2001 From: Laura Beatris <48022589+LauraBeatris@users.noreply.github.com> Date: Wed, 1 Oct 2025 19:52:00 -0300 Subject: [PATCH 2/9] Update types --- packages/types/src/organizationSettings.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/types/src/organizationSettings.ts b/packages/types/src/organizationSettings.ts index afbe09c5c97..b25a954c6fa 100644 --- a/packages/types/src/organizationSettings.ts +++ b/packages/types/src/organizationSettings.ts @@ -17,6 +17,9 @@ export interface OrganizationSettingsJSON extends ClerkResourceJSON { enrollment_modes: OrganizationEnrollmentMode[]; default_role: string | null; }; + slugs: { + disabled: boolean; + }; } export interface OrganizationSettingsResource extends ClerkResource { @@ -31,5 +34,8 @@ export interface OrganizationSettingsResource extends ClerkResource { enrollmentModes: OrganizationEnrollmentMode[]; defaultRole: string | null; }; + slugs: { + disabled: boolean; + }; __internal_toSnapshot: () => OrganizationSettingsJSONSnapshot; } From a6987762bd4569650a83464773d8094b79943624 Mon Sep 17 00:00:00 2001 From: Laura Beatris <48022589+LauraBeatris@users.noreply.github.com> Date: Wed, 1 Oct 2025 19:52:27 -0300 Subject: [PATCH 3/9] Conditionally display field on `CreateOrganization` form --- .../CreateOrganization/CreateOrganizationForm.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationForm.tsx b/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationForm.tsx index bb909e3aa7e..0eff6526fc6 100644 --- a/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationForm.tsx +++ b/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationForm.tsx @@ -2,6 +2,7 @@ import { useOrganization, useOrganizationList } from '@clerk/shared/react'; import type { CreateOrganizationParams, OrganizationResource } from '@clerk/types'; import React from 'react'; +import { useEnvironment } from '@/ui/contexts'; import { useCardState, withCardStateProvider } from '@/ui/elements/contexts'; import { Form } from '@/ui/elements/Form'; import { FormButtonContainer } from '@/ui/elements/FormButtons'; @@ -45,6 +46,7 @@ export const CreateOrganizationForm = withCardStateProvider((props: CreateOrgani userMemberships: organizationListParams.userMemberships, }); const { organization } = useOrganization(); + const { organizationSettings } = useEnvironment(); const [file, setFile] = React.useState(); const nameField = useFormControl('name', '', { @@ -61,6 +63,7 @@ export const CreateOrganizationForm = withCardStateProvider((props: CreateOrgani const dataChanged = !!nameField.value; const canSubmit = dataChanged; + const organizationSlugEnabled = !props.hideSlug || !organizationSettings.slugs.disabled; const onSubmit = async (e: React.FormEvent) => { e.preventDefault(); @@ -75,7 +78,7 @@ export const CreateOrganizationForm = withCardStateProvider((props: CreateOrgani try { const createOrgParams: CreateOrganizationParams = { name: nameField.value }; - if (!props.hideSlug) { + if (organizationSlugEnabled) { createOrgParams.slug = slugField.value; } @@ -188,7 +191,7 @@ export const CreateOrganizationForm = withCardStateProvider((props: CreateOrgani ignorePasswordManager /> - {!props.hideSlug && ( + {organizationSlugEnabled && ( Date: Wed, 1 Oct 2025 20:08:42 -0300 Subject: [PATCH 4/9] Deprecate `hideSlug` prop --- .../src/core/resources/OrganizationSettings.ts | 6 +++--- .../CreateOrganization/CreateOrganizationForm.tsx | 7 ++++++- packages/types/src/clerk.ts | 15 +++++++++------ packages/types/src/organizationSettings.ts | 4 ++-- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/packages/clerk-js/src/core/resources/OrganizationSettings.ts b/packages/clerk-js/src/core/resources/OrganizationSettings.ts index 2281deb9ba4..6c8dfa4d814 100644 --- a/packages/clerk-js/src/core/resources/OrganizationSettings.ts +++ b/packages/clerk-js/src/core/resources/OrganizationSettings.ts @@ -18,7 +18,7 @@ export class OrganizationSettings extends BaseResource implements OrganizationSe enrollmentModes: [], defaultRole: null, }; - slugs: { + slug: { disabled: boolean; } = { disabled: false, @@ -47,8 +47,8 @@ export class OrganizationSettings extends BaseResource implements OrganizationSe this.domains.defaultRole = this.withDefault(data.domains.default_role, this.domains.defaultRole); } - if (data.slugs) { - this.slugs.disabled = this.withDefault(data.slugs.disabled, this.slugs.disabled); + if (data.slug) { + this.slug.disabled = this.withDefault(data.slug.disabled, this.slug.disabled); } this.enabled = this.withDefault(data.enabled, this.enabled); diff --git a/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationForm.tsx b/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationForm.tsx index 0eff6526fc6..8598b4a1fcc 100644 --- a/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationForm.tsx +++ b/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationForm.tsx @@ -34,6 +34,11 @@ type CreateOrganizationFormProps = { headerTitle?: LocalizationKey; headerSubtitle?: LocalizationKey; }; + /** + * @deprecated + * This prop will be removed in a future version. + * Configure whether organization slug is required via the Clerk Dashboard under Organization Settings. + */ hideSlug?: boolean; }; @@ -63,7 +68,7 @@ export const CreateOrganizationForm = withCardStateProvider((props: CreateOrgani const dataChanged = !!nameField.value; const canSubmit = dataChanged; - const organizationSlugEnabled = !props.hideSlug || !organizationSettings.slugs.disabled; + const organizationSlugEnabled = !props.hideSlug || !organizationSettings.slug.disabled; const onSubmit = async (e: React.FormEvent) => { e.preventDefault(); diff --git a/packages/types/src/clerk.ts b/packages/types/src/clerk.ts index fcf84df542f..0c0694e070e 100644 --- a/packages/types/src/clerk.ts +++ b/packages/types/src/clerk.ts @@ -1561,8 +1561,9 @@ export type CreateOrganizationProps = RoutingOptions & { */ appearance?: CreateOrganizationTheme; /** - * Hides the optional "slug" field in the organization creation screen. - * @default false + * @deprecated + * This prop will be removed in a future version. + * Configure whether organization slug is required via the Clerk Dashboard under Organization Settings. */ hideSlug?: boolean; }; @@ -1721,8 +1722,9 @@ export type OrganizationSwitcherProps = CreateOrganizationMode & */ skipInvitationScreen?: boolean; /** - * Hides the optional "slug" field in the organization creation screen. - * @default false + * @deprecated + * This prop will be removed in a future version. + * Configure whether organization slug is required via the Clerk Dashboard under Organization Settings. */ hideSlug?: boolean; /** @@ -1781,8 +1783,9 @@ export type OrganizationListProps = { */ afterSelectPersonalUrl?: ((user: UserResource) => string) | LooseExtractedParams>; /** - * Hides the optional "slug" field in the organization creation screen. - * @default false + * @deprecated + * This prop will be removed in a future version. + * Configure whether organization slug is required via the Clerk Dashboard under Organization Settings. */ hideSlug?: boolean; }; diff --git a/packages/types/src/organizationSettings.ts b/packages/types/src/organizationSettings.ts index b25a954c6fa..ab9e0704e1e 100644 --- a/packages/types/src/organizationSettings.ts +++ b/packages/types/src/organizationSettings.ts @@ -17,7 +17,7 @@ export interface OrganizationSettingsJSON extends ClerkResourceJSON { enrollment_modes: OrganizationEnrollmentMode[]; default_role: string | null; }; - slugs: { + slug: { disabled: boolean; }; } @@ -34,7 +34,7 @@ export interface OrganizationSettingsResource extends ClerkResource { enrollmentModes: OrganizationEnrollmentMode[]; defaultRole: string | null; }; - slugs: { + slug: { disabled: boolean; }; __internal_toSnapshot: () => OrganizationSettingsJSONSnapshot; From 5f107924a17119c88bb51e8e8c3c89fab8910aa2 Mon Sep 17 00:00:00 2001 From: Laura Beatris <48022589+LauraBeatris@users.noreply.github.com> Date: Wed, 1 Oct 2025 20:29:22 -0300 Subject: [PATCH 5/9] Conditionally display field on `TaskChooseOrganization` form --- .../CreateOrganizationScreen.tsx | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskChooseOrganization/CreateOrganizationScreen.tsx b/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskChooseOrganization/CreateOrganizationScreen.tsx index 14afd0c8913..55019e6a966 100644 --- a/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskChooseOrganization/CreateOrganizationScreen.tsx +++ b/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskChooseOrganization/CreateOrganizationScreen.tsx @@ -1,5 +1,7 @@ import { useOrganizationList } from '@clerk/shared/react'; +import type { CreateOrganizationParams } from '@clerk/types'; +import { useEnvironment } from '@/ui/contexts'; import { useTaskChooseOrganizationContext } from '@/ui/contexts/components/SessionTasks'; import { localizationKeys } from '@/ui/customizables'; import { useCardState } from '@/ui/elements/contexts'; @@ -25,6 +27,7 @@ export const CreateOrganizationScreen = (props: CreateOrganizationScreenProps) = const { createOrganization, isLoaded, setActive } = useOrganizationList({ userMemberships: organizationListParams.userMemberships, }); + const { organizationSettings } = useEnvironment(); const nameField = useFormControl('name', '', { type: 'text', @@ -37,6 +40,8 @@ export const CreateOrganizationScreen = (props: CreateOrganizationScreenProps) = placeholder: localizationKeys('taskChooseOrganization.createOrganization.formFieldInputPlaceholder__slug'), }); + const organizationSlugEnabled = !organizationSettings.slug.disabled; + const onSubmit = async (e: React.FormEvent) => { e.preventDefault(); @@ -45,7 +50,13 @@ export const CreateOrganizationScreen = (props: CreateOrganizationScreenProps) = } try { - const organization = await createOrganization({ name: nameField.value, slug: slugField.value }); + const createOrgParams: CreateOrganizationParams = { name: nameField.value }; + + if (organizationSlugEnabled) { + createOrgParams.slug = slugField.value; + } + + const organization = await createOrganization(createOrgParams); await setActive({ organization, @@ -90,15 +101,17 @@ export const CreateOrganizationScreen = (props: CreateOrganizationScreenProps) = ignorePasswordManager /> - - updateSlugField(event.target.value)} - isRequired - pattern='^(?=.*[a-z0-9])[a-z0-9\-]+$' - ignorePasswordManager - /> - + {organizationSlugEnabled && ( + + updateSlugField(event.target.value)} + isRequired + pattern='^(?=.*[a-z0-9])[a-z0-9\-]+$' + ignorePasswordManager + /> + + )} ({ flexDirection: 'column' })}> Date: Wed, 1 Oct 2025 20:40:03 -0300 Subject: [PATCH 6/9] Add UI tests --- packages/clerk-js/src/test/fixture-helpers.ts | 11 ++- .../__tests__/CreateOrganization.test.tsx | 80 ++++++++++++++----- .../__tests__/TaskChooseOrganization.test.tsx | 34 ++++++++ 3 files changed, 102 insertions(+), 23 deletions(-) diff --git a/packages/clerk-js/src/test/fixture-helpers.ts b/packages/clerk-js/src/test/fixture-helpers.ts index 847e3dedab2..143e7e6a7c3 100644 --- a/packages/clerk-js/src/test/fixture-helpers.ts +++ b/packages/clerk-js/src/test/fixture-helpers.ts @@ -342,13 +342,22 @@ const createOrganizationSettingsFixtureHelpers = (environment: EnvironmentJSON) const withForceOrganizationSelection = () => { os.force_organization_selection = true; }; + const withOrganizationSlug = (enabled = false) => { + os.slug.disabled = !enabled; + }; const withOrganizationDomains = (modes?: OrganizationEnrollmentMode[], defaultRole?: string) => { os.domains.enabled = true; os.domains.enrollment_modes = modes || ['automatic_invitation', 'manual_invitation']; os.domains.default_role = defaultRole ?? null; }; - return { withOrganizations, withMaxAllowedMemberships, withOrganizationDomains, withForceOrganizationSelection }; + return { + withOrganizations, + withMaxAllowedMemberships, + withOrganizationDomains, + withForceOrganizationSelection, + withOrganizationSlug, + }; }; const createBillingSettingsFixtureHelpers = (environment: EnvironmentJSON) => { diff --git a/packages/clerk-js/src/ui/components/CreateOrganization/__tests__/CreateOrganization.test.tsx b/packages/clerk-js/src/ui/components/CreateOrganization/__tests__/CreateOrganization.test.tsx index 3e6b9a0681e..8e3226f987c 100644 --- a/packages/clerk-js/src/ui/components/CreateOrganization/__tests__/CreateOrganization.test.tsx +++ b/packages/clerk-js/src/ui/components/CreateOrganization/__tests__/CreateOrganization.test.tsx @@ -80,35 +80,71 @@ describe('CreateOrganization', () => { expect(getByRole('heading', { name: 'Create organization', level: 1 })).toBeInTheDocument(); }); - it('renders component without slug field', async () => { - const { wrapper, fixtures, props } = await createFixtures(f => { - f.withOrganizations(); - f.withUser({ - email_addresses: ['test@clerk.com'], + describe('with `hideSlug` prop', () => { + it('renders component without slug field', async () => { + const { wrapper, fixtures, props } = await createFixtures(f => { + f.withOrganizations(); + f.withUser({ + email_addresses: ['test@clerk.com'], + }); }); - }); - fixtures.clerk.createOrganization.mockReturnValue( - Promise.resolve( - getCreatedOrg({ - maxAllowedMemberships: 1, - slug: 'new-org-1722578361', - }), - ), - ); + fixtures.clerk.createOrganization.mockReturnValue( + Promise.resolve( + getCreatedOrg({ + maxAllowedMemberships: 1, + slug: 'new-org-1722578361', + }), + ), + ); + + props.setProps({ hideSlug: true }); + const { userEvent, getByRole, queryByText, queryByLabelText, getByLabelText } = render(, { + wrapper, + }); - props.setProps({ hideSlug: true }); - const { userEvent, getByRole, queryByText, queryByLabelText, getByLabelText } = render(, { - wrapper, + expect(queryByLabelText(/Slug/i)).not.toBeInTheDocument(); + + await userEvent.type(getByLabelText(/Name/i), 'new org'); + await userEvent.click(getByRole('button', { name: /create organization/i })); + + await waitFor(() => { + expect(queryByText(/Invite new members/i)).toBeInTheDocument(); + }); }); + }); - expect(queryByLabelText(/Slug/i)).not.toBeInTheDocument(); + describe('with organization slug disabled on environment', () => { + it('renders component without slug field', async () => { + const { wrapper, fixtures } = await createFixtures(f => { + f.withOrganizations(); + f.withOrganizationSlug(false); + f.withUser({ + email_addresses: ['test@clerk.com'], + }); + }); - await userEvent.type(getByLabelText(/Name/i), 'new org'); - await userEvent.click(getByRole('button', { name: /create organization/i })); + fixtures.clerk.createOrganization.mockReturnValue( + Promise.resolve( + getCreatedOrg({ + maxAllowedMemberships: 1, + slug: 'new-org-1722578361', + }), + ), + ); - await waitFor(() => { - expect(queryByText(/Invite new members/i)).toBeInTheDocument(); + const { userEvent, getByRole, queryByText, queryByLabelText, getByLabelText } = render(, { + wrapper, + }); + + expect(queryByLabelText(/Slug/i)).not.toBeInTheDocument(); + + await userEvent.type(getByLabelText(/Name/i), 'new org'); + await userEvent.click(getByRole('button', { name: /create organization/i })); + + await waitFor(() => { + expect(queryByText(/Invite new members/i)).toBeInTheDocument(); + }); }); }); diff --git a/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskChooseOrganization/__tests__/TaskChooseOrganization.test.tsx b/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskChooseOrganization/__tests__/TaskChooseOrganization.test.tsx index 3b5f05c275b..fee3ffcfa94 100644 --- a/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskChooseOrganization/__tests__/TaskChooseOrganization.test.tsx +++ b/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskChooseOrganization/__tests__/TaskChooseOrganization.test.tsx @@ -204,4 +204,38 @@ describe('TaskChooseOrganization', () => { expect(await findByText(/testuser/)).toBeInTheDocument(); }); + + describe('on create organization form', () => { + it("does not display slug field if it's disabled on environment", async () => { + const { wrapper } = await createFixtures(f => { + f.withOrganizations(); + f.withOrganizationSlug(false); + f.withForceOrganizationSelection(); + f.withUser({ + create_organization_enabled: true, + tasks: [{ key: 'choose-organization' }], + }); + }); + + const { queryByLabelText } = render(, { wrapper }); + + expect(queryByLabelText(/Slug/i)).not.toBeInTheDocument(); + }); + }); + + it("display slug field if it's enabled on environment", async () => { + const { wrapper } = await createFixtures(f => { + f.withOrganizations(); + f.withOrganizationSlug(true); + f.withForceOrganizationSelection(); + f.withUser({ + create_organization_enabled: true, + tasks: [{ key: 'choose-organization' }], + }); + }); + + const { queryByLabelText } = render(, { wrapper }); + + expect(queryByLabelText(/Slug/i)).toBeInTheDocument(); + }); }); From 463110e3fb275f3a5869831cffd22903bce2c123 Mon Sep 17 00:00:00 2001 From: Laura Beatris <48022589+LauraBeatris@users.noreply.github.com> Date: Wed, 1 Oct 2025 20:42:40 -0300 Subject: [PATCH 7/9] Add changeset --- .changeset/dull-paws-march.md | 6 ++++++ packages/clerk-js/src/test/fixtures.ts | 3 +++ .../CreateOrganization/CreateOrganizationForm.tsx | 4 +++- 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 .changeset/dull-paws-march.md diff --git a/.changeset/dull-paws-march.md b/.changeset/dull-paws-march.md new file mode 100644 index 00000000000..f6d68bea87a --- /dev/null +++ b/.changeset/dull-paws-march.md @@ -0,0 +1,6 @@ +--- +'@clerk/clerk-js': patch +'@clerk/types': patch +--- + +Display organization slug based on environment settings diff --git a/packages/clerk-js/src/test/fixtures.ts b/packages/clerk-js/src/test/fixtures.ts index 1edd74561f7..8fd8c659558 100644 --- a/packages/clerk-js/src/test/fixtures.ts +++ b/packages/clerk-js/src/test/fixtures.ts @@ -89,6 +89,9 @@ const createBaseOrganizationSettings = (): OrganizationSettingsJSON => { enabled: false, enrollment_modes: [], }, + slug: { + disabled: true, + }, } as unknown as OrganizationSettingsJSON; }; diff --git a/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationForm.tsx b/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationForm.tsx index 8598b4a1fcc..f81f17a54c3 100644 --- a/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationForm.tsx +++ b/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationForm.tsx @@ -68,7 +68,9 @@ export const CreateOrganizationForm = withCardStateProvider((props: CreateOrgani const dataChanged = !!nameField.value; const canSubmit = dataChanged; - const organizationSlugEnabled = !props.hideSlug || !organizationSettings.slug.disabled; + + // Environment setting takes precedence over prop + const organizationSlugEnabled = !organizationSettings.slug.disabled && !props.hideSlug; const onSubmit = async (e: React.FormEvent) => { e.preventDefault(); From 9114833992fabe60e92af6a42a1697ce981ba6c3 Mon Sep 17 00:00:00 2001 From: Laura Beatris <48022589+LauraBeatris@users.noreply.github.com> Date: Thu, 2 Oct 2025 14:47:51 -0300 Subject: [PATCH 8/9] Fix unit tests --- .../__tests__/CreateOrganization.test.tsx | 102 +++++++++++++++++- .../__tests__/OrganizationList.test.tsx | 2 + .../__tests__/TaskChooseOrganization.test.tsx | 28 ++--- 3 files changed, 117 insertions(+), 15 deletions(-) diff --git a/packages/clerk-js/src/ui/components/CreateOrganization/__tests__/CreateOrganization.test.tsx b/packages/clerk-js/src/ui/components/CreateOrganization/__tests__/CreateOrganization.test.tsx index 8e3226f987c..4c038efb9f5 100644 --- a/packages/clerk-js/src/ui/components/CreateOrganization/__tests__/CreateOrganization.test.tsx +++ b/packages/clerk-js/src/ui/components/CreateOrganization/__tests__/CreateOrganization.test.tsx @@ -114,8 +114,8 @@ describe('CreateOrganization', () => { }); }); - describe('with organization slug disabled on environment', () => { - it('renders component without slug field', async () => { + describe('with organization slug configured on environment', () => { + it('when disabled, renders component without slug field', async () => { const { wrapper, fixtures } = await createFixtures(f => { f.withOrganizations(); f.withOrganizationSlug(false); @@ -146,6 +146,104 @@ describe('CreateOrganization', () => { expect(queryByText(/Invite new members/i)).toBeInTheDocument(); }); }); + + it('when enabled, renders component slug field', async () => { + const { wrapper, fixtures } = await createFixtures(f => { + f.withOrganizations(); + f.withOrganizationSlug(true); + f.withUser({ + email_addresses: ['test@clerk.com'], + }); + }); + + fixtures.clerk.createOrganization.mockReturnValue( + Promise.resolve( + getCreatedOrg({ + maxAllowedMemberships: 1, + slug: 'new-org-1722578361', + }), + ), + ); + + const { userEvent, getByRole, queryByText, queryByLabelText, getByLabelText } = render(, { + wrapper, + }); + + expect(queryByLabelText(/Slug/i)).toBeInTheDocument(); + + await userEvent.type(getByLabelText(/Name/i), 'new org'); + await userEvent.click(getByRole('button', { name: /create organization/i })); + + await waitFor(() => { + expect(queryByText(/Invite new members/i)).toBeInTheDocument(); + }); + }); + + it('when enabled and `hideSlug` prop is passed, renders component without slug field', async () => { + const { wrapper, fixtures, props } = await createFixtures(f => { + f.withOrganizations(); + f.withOrganizationSlug(true); + f.withUser({ + email_addresses: ['test@clerk.com'], + }); + }); + + fixtures.clerk.createOrganization.mockReturnValue( + Promise.resolve( + getCreatedOrg({ + maxAllowedMemberships: 1, + slug: 'new-org-1722578361', + }), + ), + ); + + props.setProps({ hideSlug: true }); + const { userEvent, getByRole, queryByText, queryByLabelText, getByLabelText } = render(, { + wrapper, + }); + + expect(queryByLabelText(/Slug/i)).not.toBeInTheDocument(); + + await userEvent.type(getByLabelText(/Name/i), 'new org'); + await userEvent.click(getByRole('button', { name: /create organization/i })); + + await waitFor(() => { + expect(queryByText(/Invite new members/i)).toBeInTheDocument(); + }); + }); + + it('when disabled and `hideSlug` prop is passed, renders component without slug field', async () => { + const { wrapper, fixtures, props } = await createFixtures(f => { + f.withOrganizations(); + f.withOrganizationSlug(false); // Environment disables slug + f.withUser({ + email_addresses: ['test@clerk.com'], + }); + }); + + fixtures.clerk.createOrganization.mockReturnValue( + Promise.resolve( + getCreatedOrg({ + maxAllowedMemberships: 1, + slug: 'new-org-1722578361', + }), + ), + ); + + props.setProps({ hideSlug: true }); + const { userEvent, getByRole, queryByText, queryByLabelText, getByLabelText } = render(, { + wrapper, + }); + + expect(queryByLabelText(/Slug/i)).not.toBeInTheDocument(); + + await userEvent.type(getByLabelText(/Name/i), 'new org'); + await userEvent.click(getByRole('button', { name: /create organization/i })); + + await waitFor(() => { + expect(queryByText(/Invite new members/i)).toBeInTheDocument(); + }); + }); }); it('skips invitation screen', async () => { diff --git a/packages/clerk-js/src/ui/components/OrganizationList/__tests__/OrganizationList.test.tsx b/packages/clerk-js/src/ui/components/OrganizationList/__tests__/OrganizationList.test.tsx index 63cfcc228ce..09ad363316b 100644 --- a/packages/clerk-js/src/ui/components/OrganizationList/__tests__/OrganizationList.test.tsx +++ b/packages/clerk-js/src/ui/components/OrganizationList/__tests__/OrganizationList.test.tsx @@ -85,6 +85,7 @@ describe('OrganizationList', () => { it('hides the personal account with no data to list', async () => { const { wrapper, props } = await createFixtures(f => { f.withOrganizations(); + f.withOrganizationSlug(true); f.withUser({ email_addresses: ['test@clerk.com'], organization_memberships: [{ name: 'Org1', id: '1', role: 'admin' }], @@ -210,6 +211,7 @@ describe('OrganizationList', () => { it('display CreateOrganization within OrganizationList', async () => { const { wrapper } = await createFixtures(f => { f.withOrganizations(); + f.withOrganizationSlug(true); f.withUser({ email_addresses: ['test@clerk.com'], create_organization_enabled: true, diff --git a/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskChooseOrganization/__tests__/TaskChooseOrganization.test.tsx b/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskChooseOrganization/__tests__/TaskChooseOrganization.test.tsx index fee3ffcfa94..b0604a57582 100644 --- a/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskChooseOrganization/__tests__/TaskChooseOrganization.test.tsx +++ b/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskChooseOrganization/__tests__/TaskChooseOrganization.test.tsx @@ -217,25 +217,27 @@ describe('TaskChooseOrganization', () => { }); }); - const { queryByLabelText } = render(, { wrapper }); + const { findByRole, queryByLabelText } = render(, { wrapper }); + expect(await findByRole('textbox', { name: /name/i })).toBeInTheDocument(); expect(queryByLabelText(/Slug/i)).not.toBeInTheDocument(); }); - }); - it("display slug field if it's enabled on environment", async () => { - const { wrapper } = await createFixtures(f => { - f.withOrganizations(); - f.withOrganizationSlug(true); - f.withForceOrganizationSelection(); - f.withUser({ - create_organization_enabled: true, - tasks: [{ key: 'choose-organization' }], + it("display slug field if it's enabled on environment", async () => { + const { wrapper } = await createFixtures(f => { + f.withOrganizations(); + f.withOrganizationSlug(true); + f.withForceOrganizationSelection(); + f.withUser({ + create_organization_enabled: true, + tasks: [{ key: 'choose-organization' }], + }); }); - }); - const { queryByLabelText } = render(, { wrapper }); + const { findByRole, queryByLabelText } = render(, { wrapper }); - expect(queryByLabelText(/Slug/i)).toBeInTheDocument(); + expect(await findByRole('textbox', { name: /name/i })).toBeInTheDocument(); + expect(queryByLabelText(/Slug/i)).toBeInTheDocument(); + }); }); }); From bd59a62eae8e08711427c7e0b5c31f7487767724 Mon Sep 17 00:00:00 2001 From: Laura Beatris <48022589+LauraBeatris@users.noreply.github.com> Date: Fri, 3 Oct 2025 13:31:17 -0300 Subject: [PATCH 9/9] Update JSDocs according to Dashboard UI --- .../CreateOrganization/CreateOrganizationForm.tsx | 2 +- packages/types/src/clerk.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationForm.tsx b/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationForm.tsx index f81f17a54c3..bed14d233f8 100644 --- a/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationForm.tsx +++ b/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationForm.tsx @@ -37,7 +37,7 @@ type CreateOrganizationFormProps = { /** * @deprecated * This prop will be removed in a future version. - * Configure whether organization slug is required via the Clerk Dashboard under Organization Settings. + * Configure whether organization slug is enabled via the Clerk Dashboard under Organization Settings. */ hideSlug?: boolean; }; diff --git a/packages/types/src/clerk.ts b/packages/types/src/clerk.ts index 0c0694e070e..5140c03f27a 100644 --- a/packages/types/src/clerk.ts +++ b/packages/types/src/clerk.ts @@ -1563,7 +1563,7 @@ export type CreateOrganizationProps = RoutingOptions & { /** * @deprecated * This prop will be removed in a future version. - * Configure whether organization slug is required via the Clerk Dashboard under Organization Settings. + * Configure whether organization slug is enabled via the Clerk Dashboard under Organization Settings. */ hideSlug?: boolean; }; @@ -1724,7 +1724,7 @@ export type OrganizationSwitcherProps = CreateOrganizationMode & /** * @deprecated * This prop will be removed in a future version. - * Configure whether organization slug is required via the Clerk Dashboard under Organization Settings. + * Configure whether organization slug is enabled via the Clerk Dashboard under Organization Settings. */ hideSlug?: boolean; /** @@ -1785,7 +1785,7 @@ export type OrganizationListProps = { /** * @deprecated * This prop will be removed in a future version. - * Configure whether organization slug is required via the Clerk Dashboard under Organization Settings. + * Configure whether organization slug is enabled via the Clerk Dashboard under Organization Settings. */ hideSlug?: boolean; };