@vtex/faststore-plugin-buyer-portal 2.0.13 → 2.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -1
- package/cms/b2b/components/.gitkeep +0 -0
- package/cms/b2b/pages/cms_content_type__i18n.jsonc +36 -0
- package/cypress/integration/localization.test.ts +482 -0
- package/cypress/support/commands.ts +8 -0
- package/docs/i18n/i18n-messages-format.md +391 -0
- package/docs/i18n/locales.json +701 -0
- package/docs/i18n/migration-inventory.md +959 -0
- package/package.json +3 -3
- package/specs/custom-localization-system.md +711 -0
- package/specs/multi-locale-e2e-validation.md +277 -0
- package/src/__mocks__/discovery.config.ts +12 -0
- package/src/features/accounting-fields/components/AccountingConfirmDelete/AccountingConfirmDelete.tsx +14 -4
- package/src/features/accounting-fields/components/AccountingFieldConfirmEdit/AccountingFieldConfirmEdit.tsx +11 -6
- package/src/features/accounting-fields/components/AccountingFieldDropdown/AccountingFieldDropdown.tsx +5 -3
- package/src/features/accounting-fields/components/AccountingFieldForm/AccountingFieldForm.tsx +33 -23
- package/src/features/accounting-fields/components/AccountingValueConfirmEdit/AccountingValueConfirmEdit.tsx +10 -6
- package/src/features/accounting-fields/components/AccountingValueDropdown/AccountingValueDropdown.tsx +19 -9
- package/src/features/accounting-fields/components/AccountingValueForm/AccountingValueForm.tsx +21 -10
- package/src/features/accounting-fields/components/CreateAccountingFieldDrawer/CreateAccountingFieldDrawer.tsx +11 -8
- package/src/features/accounting-fields/components/CreateAccountingValueDrawer/CreateAccountingValueDrawer.tsx +18 -7
- package/src/features/accounting-fields/components/DeleteAccountingFieldDrawer/DeleteAccountingFieldDrawer.tsx +14 -12
- package/src/features/accounting-fields/components/DeleteAccountingValueDrawer/DeleteAccountingValueDrawer.tsx +20 -10
- package/src/features/accounting-fields/components/EditAccountingFieldDrawer/EditAccountingFieldDrawer.tsx +5 -3
- package/src/features/accounting-fields/components/EditAccountingValueDrawer/EditAccountingValueDrawer.tsx +13 -6
- package/src/features/accounting-fields/components/RemoveValueFromUnitDrawer/RemoveValueFromUnitDrawer.tsx +19 -8
- package/src/features/accounting-fields/layouts/AccountingFieldLayout/AccountingFieldLayout.tsx +11 -9
- package/src/features/addresses/components/AddRecipientsDrawer/AddRecipientsDrawer.tsx +13 -7
- package/src/features/addresses/components/AddressDropdownMenu/AddressDropdownMenu.tsx +22 -20
- package/src/features/addresses/components/AddressForm/AddressForm.tsx +33 -22
- package/src/features/addresses/components/AddressLine/AddressLine.tsx +29 -25
- package/src/features/addresses/components/AddressLocationsList/AddressLocationsList.tsx +15 -6
- package/src/features/addresses/components/AddressRecipientsList/AddressRecipientsList.tsx +9 -4
- package/src/features/addresses/components/AddressesCard/AddressesCard.tsx +8 -5
- package/src/features/addresses/components/CreateAddressDrawer/CreateAddressDrawer.tsx +27 -14
- package/src/features/addresses/components/CreateAddressSettingsDrawer/CreateAddressSettingsDrawer.tsx +26 -21
- package/src/features/addresses/components/DeleteAddressDrawer/DeleteAddressDrawer.tsx +20 -16
- package/src/features/addresses/components/DeleteAddressLocationDrawer/DeleteAddressLocationDrawer.tsx +26 -14
- package/src/features/addresses/components/DeleteRecipientAddressDrawer/DeleteRecipientAddressDrawer.tsx +20 -17
- package/src/features/addresses/components/EditAddressDrawer/EditAddressDrawer.tsx +12 -6
- package/src/features/addresses/components/EditAddressLocationDrawer/EditAddressLocationDrawer.tsx +24 -17
- package/src/features/addresses/components/EditRecipientAddressDrawer/EditRecipientAddressDrawer.tsx +17 -15
- package/src/features/addresses/components/LocationForm/LocationField/LocationField.tsx +8 -5
- package/src/features/addresses/components/LocationForm/LocationForm.tsx +9 -3
- package/src/features/addresses/components/LocationsDrawer/LocationsDrawer.tsx +15 -9
- package/src/features/addresses/components/RecipientsForm/RecipientItem/RecipientItem.tsx +55 -46
- package/src/features/addresses/components/RecipientsForm/RecipientsForm.tsx +4 -1
- package/src/features/addresses/components/RemoveAddressDrawer/RemoveAddressDrawer.tsx +21 -14
- package/src/features/addresses/layouts/AddressDetailsLayout/AddressDetailsLayout.tsx +16 -9
- package/src/features/addresses/layouts/AddressesLayout/AddressesLayout.tsx +11 -8
- package/src/features/b2b-agent/layouts/B2BAgentLayout/B2BAgentLayout.tsx +3 -1
- package/src/features/budgets/components/BudgetAddForm/BudgetAddForm.tsx +14 -12
- package/src/features/budgets/components/BudgetAddSuccess/BudgetAddSuccess.tsx +16 -14
- package/src/features/budgets/components/BudgetAllocationsSelection/BudgetAllocationsSelection.tsx +8 -5
- package/src/features/budgets/components/BudgetAllocationsTable/BudgetAllocationsTable.tsx +9 -6
- package/src/features/budgets/components/BudgetDeleteDrawer/BudgetDeleteDrawer.tsx +23 -17
- package/src/features/budgets/components/BudgetEditNotificationDrawer/BudgetEditNotificationDrawer.tsx +13 -6
- package/src/features/budgets/components/BudgetNotificationForm/BudgetNotificationForm.tsx +31 -24
- package/src/features/budgets/components/BudgetNotificationsInfo/BudgetNotificationsInfo.tsx +15 -9
- package/src/features/budgets/components/BudgetRemainingBalance/BudgetRemainingBalance.tsx +6 -2
- package/src/features/budgets/components/BudgetSettingsInfo/BudgetSettingsInfo.tsx +27 -10
- package/src/features/budgets/components/BudgetUsersTable/BudgetUsersTable.tsx +14 -7
- package/src/features/budgets/components/BudgetsTable/BudgetsTable.tsx +11 -8
- package/src/features/budgets/components/CreateBudgetAllocationDrawer/CreateBudgetAllocationDrawer.tsx +8 -5
- package/src/features/budgets/components/CreateBudgetDrawer/CreateBudgetDrawer.tsx +31 -18
- package/src/features/budgets/components/DeleteBudgetAllocationDrawer/DeleteBudgetAllocationDrawer.tsx +17 -12
- package/src/features/budgets/components/EditBudgetDrawer/EditBudgetDrawer.tsx +14 -8
- package/src/features/budgets/components/EmptyState.tsx/EmptyState.tsx +4 -1
- package/src/features/budgets/layouts/BudgetsDetailsLayout/BudgetsDetailsLayout.tsx +7 -5
- package/src/features/budgets/layouts/BudgetsLayout/BudgetsLayout.tsx +5 -3
- package/src/features/budgets/messages/budgetNotifications.ts +5 -5
- package/src/features/budgets/utils/handleBudgetError.tsx +5 -8
- package/src/features/budgets/utils/handleBudgetError.types.ts +3 -0
- package/src/features/buying-policies/components/AccountingFieldCriteriaSelector/AccountingFieldCriteriaSelector.tsx +5 -3
- package/src/features/buying-policies/components/AccountingFieldCriteriaSelector/AccountingValueCriteriaSelector.tsx +20 -9
- package/src/features/buying-policies/components/AddBuyingPolicyDrawer/AddBuyingPolicyDrawer.tsx +8 -5
- package/src/features/buying-policies/components/BasicBuyingPolicyDrawer/BasicBuyingPolicyDrawer.tsx +49 -33
- package/src/features/buying-policies/components/BudgetCriteriaSelector/BudgetCriteriaSelector.tsx +8 -2
- package/src/features/buying-policies/components/BuyingPolicyDropdownMenu/BuyingPolicyDropdownMenu.tsx +5 -3
- package/src/features/buying-policies/components/DeleteBuyingPolicyDrawer/DeleteBuyingPolicyDrawer.tsx +28 -24
- package/src/features/buying-policies/components/UpdateBuyingPolicyDrawer/UpdateBuyingPolicyDrawer.tsx +10 -7
- package/src/features/buying-policies/layouts/BuyingPoliciesLayout/BuyingPoliciesLayout.tsx +11 -4
- package/src/features/buying-policies/layouts/BuyingPolicyDetailsLayout/BuyingPolicyDetailsLayout.tsx +26 -9
- package/src/features/buying-policies/utils/accountingFieldCriteriaHelpers.ts +2 -2
- package/src/features/buying-policies/utils/buyingPoliciesWorkflowTypes.ts +3 -3
- package/src/features/buying-policies/utils/orderFieldsCriteriaOptions.ts +8 -8
- package/src/features/buying-policies/utils/spendingLimitsCriteriaOptions.ts +6 -6
- package/src/features/contracts/components/ContractsCard/ContractsCard.tsx +7 -5
- package/src/features/contracts/layouts/ContractsLayout/ContractsLayout.tsx +9 -4
- package/src/features/credit-cards/components/CreateCreditCardDrawer/CreateCreditCardDrawer.tsx +17 -11
- package/src/features/credit-cards/components/CreditCardDropdownMenu/CreditCardDropdownMenu.tsx +17 -11
- package/src/features/credit-cards/components/CreditCardForm/CreditCardForm.tsx +8 -5
- package/src/features/credit-cards/components/CreditCardSettingsDrawer/CreditCardSettingsDrawer.tsx +10 -8
- package/src/features/credit-cards/components/DeleteCreditCardDrawer/DeleteCreditCardDrawer.tsx +19 -14
- package/src/features/credit-cards/components/EditCreditCardDrawer/EditCreditCardDrawer.tsx +14 -13
- package/src/features/credit-cards/components/RemoveCreditCardDrawer/RemoveCreditCardDrawer.tsx +18 -15
- package/src/features/credit-cards/layouts/CreditCardsLayout/CreditCardLayout.tsx +10 -4
- package/src/features/order-entry/layouts/OrderEntryLayout.tsx +3 -1
- package/src/features/org-units/components/AddAllToOrgUnitDropdown/AddAllToOrgUnitDropdown.tsx +11 -9
- package/src/features/org-units/components/AuthSetupDrawer/AuthSetupDrawer.tsx +28 -16
- package/src/features/org-units/components/CreateOrgUnitDrawer/CreateOrgUnitDrawer.tsx +18 -12
- package/src/features/org-units/components/DeleteOrgUnitDrawer/DeleteOrgUnitDrawer.tsx +28 -29
- package/src/features/org-units/components/OrgUnitBreadcrumb/OrgUnitBreadcrumbLink.tsx +4 -4
- package/src/features/org-units/components/OrgUnitDetailsDropdownMenu/OrgUnitDetailsDropdownMenu.tsx +4 -2
- package/src/features/org-units/components/OrgUnitDetailsNavbar/OrgUnitDetailsNavbar.tsx +23 -5
- package/src/features/org-units/components/OrgUnitDetailsNavbar/org-unit-details-navbar.scss +18 -2
- package/src/features/org-units/components/OrgUnitsDropdownMenu/OrgUnitsDropdownMenu.tsx +6 -4
- package/src/features/org-units/components/OrgUnitsHierarchyTree/OrgUnitsHierarchyTree.tsx +9 -6
- package/src/features/org-units/components/OrganizationalUnitsCard/OrganizationalUnitsCard.tsx +15 -7
- package/src/features/org-units/components/UpdateOrgUnitDrawer/UpdateOrgUnitDrawer.tsx +15 -9
- package/src/features/org-units/layouts/OrgUnitDetailsLayout/OrgUnitDetailsLayout.tsx +27 -26
- package/src/features/org-units/layouts/OrgUnitsLayout/OrgUnitsLayout.tsx +8 -3
- package/src/features/payment-methods/components/AddPaymentMethodsDrawer/AddPaymentMethodsDrawer.tsx +29 -18
- package/src/features/payment-methods/components/PaymentMethodSettingsDrawer/PaymentMethodSettingsDrawer.tsx +13 -9
- package/src/features/payment-methods/components/RemoveMethodButton/RemoveMethodButton.tsx +5 -2
- package/src/features/payment-methods/components/RemovePaymentMethodsDrawer/RemovePaymentMethodsDrawer.tsx +10 -7
- package/src/features/payment-methods/hooks/useRemovePaymentMethodSubmit.ts +6 -4
- package/src/features/payment-methods/layouts/PaymentMethodsLayout/PaymentMethodsLayout.tsx +21 -15
- package/src/features/product-assortment/components/ProductAssortmentTable/ProductAssortmentTable.tsx +11 -7
- package/src/features/product-assortment/layouts/ProductAssortmentLayout/ProductAssortmentLayout.tsx +9 -6
- package/src/features/profile/components/ProfileCard/ProfileCard.tsx +8 -5
- package/src/features/profile/components/ProfileSummary/ProfileSummary.tsx +13 -6
- package/src/features/profile/layouts/ProfileLayout/ProfileLayout.tsx +16 -6
- package/src/features/roles/layout/RoleDetailsLayout/RoleDetailsLayout.tsx +4 -2
- package/src/features/roles/layout/RolesLayout/RolesLayout.tsx +5 -3
- package/src/features/shared/components/BasicCard/BasicCard.tsx +6 -4
- package/src/features/shared/components/BasicCard/BasicCardLine.tsx +5 -4
- package/src/features/shared/components/CustomerSwitch/CustomerSwitchDrawer.tsx +10 -2
- package/src/features/shared/components/CustomerSwitch/CustomerSwitchSearch.tsx +4 -1
- package/src/features/shared/components/DropdownFilter/DropdownFilter.tsx +11 -7
- package/src/features/shared/components/Error/Error.tsx +13 -6
- package/src/features/shared/components/HeaderInside/HeaderInside.tsx +5 -2
- package/src/features/shared/components/InternalSearch/InternalSearch.tsx +4 -1
- package/src/features/shared/components/InternalTopbar/InternalTopbar.tsx +7 -5
- package/src/features/shared/components/MainLinksDropdownMenu/MainLinksDropdownMenu.tsx +23 -8
- package/src/features/shared/components/OrgUnitInputSearch/OrgUnitInputSearch.tsx +7 -2
- package/src/features/shared/components/Pagination/Pagination.tsx +6 -2
- package/src/features/shared/components/Paginator/Counter.tsx +11 -5
- package/src/features/shared/components/Paginator/Interval.tsx +4 -3
- package/src/features/shared/components/Paginator/NextPageButton.tsx +6 -2
- package/src/features/shared/components/SettingsDrawer/SettingsDrawer.tsx +6 -4
- package/src/features/shared/components/SettingsDrawer/SettingsDrawerListType.tsx +11 -10
- package/src/features/shared/components/SettingsDrawer/listTypeOptions.ts +10 -7
- package/src/features/shared/components/SortFilter/SortFilter.tsx +15 -8
- package/src/features/shared/components/Table/TableRow/TableRow.tsx +5 -1
- package/src/features/shared/components/VerticalNav/VerticalNavLink.tsx +7 -3
- package/src/features/shared/layouts/BaseTabsLayout/Navbar.tsx +28 -4
- package/src/features/shared/layouts/BaseTabsLayout/about-drawer/AboutDrawer.tsx +15 -5
- package/src/features/shared/layouts/BaseTabsLayout/base-tabs-layout.scss +24 -9
- package/src/features/shared/layouts/BaseTabsLayout/sidebar-drawer/SidebarDrawer.tsx +5 -2
- package/src/features/shared/layouts/ContractTabsLayout/ContractTabsLayout.tsx +10 -5
- package/src/features/shared/layouts/ErrorTabsLayout/ErrorTabsLayout.tsx +7 -4
- package/src/features/shared/layouts/FinanceTabsLayout/FinanceTabsLayout.tsx +9 -4
- package/src/features/shared/layouts/LoadingTabsLayout/LoadingTabsLayout.tsx +7 -4
- package/src/features/shared/layouts/OrgUnitTabsLayout/OrgUnitTabLayout.tsx +3 -0
- package/src/features/shared/layouts/SumaPageLayout/FullSidebarNav.tsx +13 -7
- package/src/features/shared/layouts/SumaPageLayout/SumaSidebar.tsx +9 -5
- package/src/features/shared/localization/LocalizationContext.tsx +35 -0
- package/src/features/shared/localization/__tests__/createLocalize.test.ts +166 -0
- package/src/features/shared/localization/__tests__/get-localization-labels.service.test.ts +202 -0
- package/src/features/shared/localization/clients/LocalizationClient.ts +19 -0
- package/src/features/shared/localization/constants.ts +31 -0
- package/src/features/shared/localization/createLocalize.ts +78 -0
- package/src/features/shared/localization/services/get-localization-labels.service.ts +76 -0
- package/src/features/shared/localization/types.ts +66 -0
- package/src/features/shared/localization/withLocalization.tsx +22 -0
- package/src/features/shared/types/AuthRouteProps.ts +5 -0
- package/src/features/shared/types/LoaderData.ts +1 -0
- package/src/features/shared/utils/addresLabelToPropMapping.ts +10 -10
- package/src/features/shared/utils/constants.ts +1 -4
- package/src/features/shared/utils/getContractSettingsLinks.ts +17 -12
- package/src/features/shared/utils/getFinanceSettingsLinks.ts +14 -9
- package/src/features/shared/utils/getKeyByValue.ts +2 -2
- package/src/features/shared/utils/getOrganizationSettingsLinks.ts +13 -3
- package/src/features/shared/utils/getSumaListingSidebarLinks.ts +15 -10
- package/src/features/shared/utils/index.ts +2 -0
- package/src/features/shared/utils/routeLayoutMapping.ts +30 -30
- package/src/features/shared/utils/search.tsx +10 -0
- package/src/features/shared/utils/withAuth.tsx +6 -0
- package/src/features/shared/utils/withAuthLoader.ts +11 -0
- package/src/features/shared/utils/withLoaderErrorBoundary.ts +9 -0
- package/src/features/shared/utils/withProviders.tsx +13 -2
- package/src/features/users/components/CreateUserDrawer/CreateUserDrawer.tsx +39 -27
- package/src/features/users/components/CreateUserDrawerWithUsername/CreateUserDrawerWithUsername.tsx +41 -39
- package/src/features/users/components/DeleteUserDrawer/DeleteUserDrawer.tsx +27 -23
- package/src/features/users/components/EmailTransactionalSection/EmailTransactionalSection.tsx +6 -8
- package/src/features/users/components/LoginField/LoginField.tsx +4 -4
- package/src/features/users/components/ReassignOrgUnitDrawer/ReassignOrgUnitDrawer.tsx +22 -19
- package/src/features/users/components/ResetPasswordDrawer/ResetPasswordDrawer.tsx +16 -21
- package/src/features/users/components/UpdateUserDrawer/UpdateUserDrawer.tsx +26 -15
- package/src/features/users/components/UpdateUserDrawerWithUsername/UpdateUserDrawerWithUsername.tsx +22 -8
- package/src/features/users/components/UserDropdownMenu/UserDropdownMenu.tsx +7 -5
- package/src/features/users/components/UserFormFields/UserFormFields.tsx +9 -8
- package/src/features/users/components/UsersCard/UsersCard.tsx +4 -2
- package/src/features/users/layouts/UserDetailsLayout/UserDetailsLayout.tsx +26 -10
- package/src/features/users/layouts/UsersLayout/UsersLayout.tsx +12 -8
- package/src/pages/accounting-field.tsx +28 -15
- package/src/pages/address-details.tsx +37 -26
- package/src/pages/addresses.tsx +27 -12
- package/src/pages/budgets-details.tsx +25 -15
- package/src/pages/budgets.tsx +31 -17
- package/src/pages/buyer-organization-manager.tsx +23 -12
- package/src/pages/buying-policies.tsx +38 -20
- package/src/pages/buying-policy-details.tsx +20 -19
- package/src/pages/contracts.tsx +15 -1
- package/src/pages/credit-cards.tsx +30 -17
- package/src/pages/order-entry.tsx +26 -15
- package/src/pages/org-unit-details.tsx +20 -6
- package/src/pages/org-units.tsx +20 -6
- package/src/pages/payment-groups.tsx +15 -12
- package/src/pages/productAssortment.tsx +10 -1
- package/src/pages/profile.tsx +14 -1
- package/src/pages/role-details.tsx +19 -6
- package/src/pages/roles.tsx +27 -14
- package/src/pages/user-details.tsx +29 -17
- package/src/pages/users.tsx +11 -0
- package/vitest.config.ts +13 -0
- package/src/features/addresses/constants/messages.ts +0 -8
- package/src/features/credit-cards/constants/messages.ts +0 -6
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.0.14] - 2026-07-21
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Custom dependency-free localization system: `LocalizationClient`, `getLocalizationLabelsService` (multi-entry merge, permanent process-local cache, single-flight dedup, graceful error fallback), `createLocalize` pure factory, `LocalizationProvider`, `useLocalization()` hook, and `withLocalization` HOC
|
|
15
|
+
- `LocalizeFn` overloaded to support `ReactNode[]` interpolation, returning alternating text/node arrays for inline JSX embedding
|
|
16
|
+
- `LOCALIZATION_ENTRY_IDS` constant map with real content-platform UUIDs for 13 feature domains
|
|
17
|
+
- `withLocalization` wired into `withProviders` before `withBuyerPortal` so labels are available across all pages
|
|
18
|
+
- CMS content-type schema for localization entries (`cms/b2b/pages/cms_content_type__i18n.jsonc`)
|
|
19
|
+
- Unit tests for `createLocalize` and `getLocalizationLabelsService` covering all spec acceptance criteria
|
|
20
|
+
- Vitest config with `discovery.config` stub alias for host-store-provided modules
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- `Navbar`'s "Start shopping" link used a hardcoded `href="/"`, dropping the selected locale; it now resolves through `useLink_unstable`'s `resolveLink()`, consistent with every other internal link in the portal
|
|
25
|
+
|
|
10
26
|
## [2.0.13] - 2026-07-21
|
|
11
27
|
|
|
12
28
|
### Fixed
|
|
@@ -770,7 +786,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
770
786
|
- Add CHANGELOG file
|
|
771
787
|
- Add README file
|
|
772
788
|
|
|
773
|
-
[unreleased]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v2.0.
|
|
789
|
+
[unreleased]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v2.0.14...HEAD
|
|
774
790
|
[1.3.55]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.54...v1.3.55
|
|
775
791
|
[1.3.54]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.53...v1.3.54
|
|
776
792
|
[1.3.53]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.52...v1.3.53
|
|
@@ -868,6 +884,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
868
884
|
[2.0.10]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v2.0.9...v2.0.10
|
|
869
885
|
[2.0.9]: https://github.com/vtex/faststore-plugin-buyer-portal/releases/tag/2.0.9
|
|
870
886
|
|
|
887
|
+
[2.0.14]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v2.0.13...v2.0.14
|
|
871
888
|
[2.0.13]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v2.0.12...v2.0.13
|
|
872
889
|
[2.0.12]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v2.0.11...v2.0.12
|
|
873
890
|
[2.0.11]: https://github.com/vtex/faststore-plugin-buyer-portal/releases/tag/2.0.11
|
|
File without changes
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"b2bLocalization": {
|
|
3
|
+
"$extends": [
|
|
4
|
+
"#/components/base-page-template"
|
|
5
|
+
],
|
|
6
|
+
"$singleton": false,
|
|
7
|
+
"type": "object",
|
|
8
|
+
"title": "B2B Localization",
|
|
9
|
+
"properties": {
|
|
10
|
+
"labels": {
|
|
11
|
+
"title": "Labels",
|
|
12
|
+
"description": "Labels for B2B Localization",
|
|
13
|
+
"type": "array",
|
|
14
|
+
"items": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"title": "Label",
|
|
17
|
+
"properties": {
|
|
18
|
+
"key": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"title": "Key"
|
|
21
|
+
},
|
|
22
|
+
"value": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"title": "Value"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
"readOnly": false,
|
|
31
|
+
"writeOnly": false,
|
|
32
|
+
"deprecated": false,
|
|
33
|
+
"$abstract": false,
|
|
34
|
+
"identifierKeys": []
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
import { TEST_CONFIG, TEST_DATA } from "../constants";
|
|
2
|
+
import { useInternalSearch } from "../shared";
|
|
3
|
+
|
|
4
|
+
const LOCALE_UNDER_TEST = "pt-BR";
|
|
5
|
+
|
|
6
|
+
// Matches CMS-key-like tokens (e.g. "users.delete.messages.confirmDeleteUser",
|
|
7
|
+
// "layouts.labels.language") that should never leak into visible UI text — `t()`
|
|
8
|
+
// only falls back to the raw key when a translation is missing.
|
|
9
|
+
const RAW_CMS_KEY_PATTERN =
|
|
10
|
+
/\b[a-zA-Z][a-zA-Z0-9]*(\.[a-zA-Z][a-zA-Z0-9]*){2,}\b/;
|
|
11
|
+
|
|
12
|
+
// Matches an unreplaced positional placeholder left over from a broken `t()` call.
|
|
13
|
+
const RAW_PLACEHOLDER_PATTERN = /\{\d+\}/;
|
|
14
|
+
|
|
15
|
+
function assertNoRawCmsKeysOrPlaceholders(selector: string) {
|
|
16
|
+
cy.get(selector)
|
|
17
|
+
.invoke("text")
|
|
18
|
+
.then((text) => {
|
|
19
|
+
const keyMatch = text.match(RAW_CMS_KEY_PATTERN);
|
|
20
|
+
assert.isNull(
|
|
21
|
+
keyMatch,
|
|
22
|
+
`found a raw CMS key in "${selector}": "${keyMatch?.[0]}"`
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const placeholderMatch = text.match(RAW_PLACEHOLDER_PATTERN);
|
|
26
|
+
assert.isNull(
|
|
27
|
+
placeholderMatch,
|
|
28
|
+
`found an unreplaced interpolation placeholder in "${selector}": "${placeholderMatch?.[0]}"`
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Switching locale mid-session (outside the selector's own Save+redirect flow, which
|
|
34
|
+
// lands on a fresh origin/session for the target binding) can leave a stale cart/session
|
|
35
|
+
// cookie bound to the previous channel — this was found to cause both an intermittent
|
|
36
|
+
// client-side validation error AND, non-deterministically, `resolveLink` rendering hrefs
|
|
37
|
+
// for the wrong (previous) locale. Visiting with only the auth cookie reflects a clean
|
|
38
|
+
// session, same as a genuinely fresh visit under the target locale, and avoids both.
|
|
39
|
+
function visitFreshUnderLocale(path: string) {
|
|
40
|
+
return cy.getCookie(TEST_CONFIG.AUTH.COOKIE_NAME).then((authCookie) => {
|
|
41
|
+
cy.clearCookies();
|
|
42
|
+
if (authCookie) {
|
|
43
|
+
cy.setCookie(TEST_CONFIG.AUTH.COOKIE_NAME, authCookie.value);
|
|
44
|
+
}
|
|
45
|
+
cy.visit(`/${LOCALE_UNDER_TEST}${path}`, { failOnStatusCode: false });
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Multi-locale delivery (B2BTEAM-3709) is rolled out per host-store environment via
|
|
50
|
+
// discovery.config's `localization.enabled` + `localization.locales`. When the target
|
|
51
|
+
// environment hasn't enabled it yet, visiting a locale-prefixed path won't resolve to
|
|
52
|
+
// the Buyer Portal. We detect that up front and skip instead of failing, so this spec
|
|
53
|
+
// stays green until the feature is live, then starts enforcing automatically.
|
|
54
|
+
function isLocalizationEnabledInThisEnvironment() {
|
|
55
|
+
return visitFreshUnderLocale(TEST_CONFIG.ROUTES.BUYER_PORTAL)
|
|
56
|
+
.get("body")
|
|
57
|
+
.then(($body) => $body.find("[data-fs-vertical-nav-menu-item]").length > 0);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Client-side (SPA) navigation between tabs can land on a stale locale — that's a
|
|
61
|
+
// separate, `@faststore/core`-level concern from what this plugin's Navbar controls.
|
|
62
|
+
// To assert exactly what `resolveLink("/")` renders for a given page, we re-request the
|
|
63
|
+
// landed-on page directly, under the locale prefix, and check the *server-rendered* href.
|
|
64
|
+
function reloadUnderLocale() {
|
|
65
|
+
return cy.location("pathname").then((pathname) => {
|
|
66
|
+
const pagePath = pathname.replace(new RegExp(`^/${LOCALE_UNDER_TEST}`), "");
|
|
67
|
+
visitFreshUnderLocale(pagePath);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
describe("Multi-locale (i18n)", { retries: 2 }, () => {
|
|
72
|
+
beforeEach(() => {
|
|
73
|
+
cy.login();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("keeps the locale prefix on the main Navbar 'Start shopping' link and breadcrumb links", () => {
|
|
77
|
+
isLocalizationEnabledInThisEnvironment().then((enabled) => {
|
|
78
|
+
if (!enabled) {
|
|
79
|
+
cy.log(
|
|
80
|
+
`Localization not enabled for locale "${LOCALE_UNDER_TEST}" in this environment — skipping.`
|
|
81
|
+
);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Navigate to a tabbed page (renders the main Navbar).
|
|
86
|
+
cy.contains("Profile").click();
|
|
87
|
+
reloadUnderLocale();
|
|
88
|
+
|
|
89
|
+
cy.get("[data-fs-bp-nav-menu-start-shopping-link]")
|
|
90
|
+
.should("have.attr", "href")
|
|
91
|
+
.and("match", new RegExp(`^/${LOCALE_UNDER_TEST}(/|$)`));
|
|
92
|
+
|
|
93
|
+
// Breadcrumb only renders a clickable (non-last) link when the current org unit
|
|
94
|
+
// has an ancestor — guard defensively since that depends on seed-data hierarchy.
|
|
95
|
+
cy.get("body").then(($body) => {
|
|
96
|
+
const breadcrumbLinks = $body.find(
|
|
97
|
+
"[data-fs-bp-breadcrumb-link] a[data-fs-bp-breadcrumb-text]"
|
|
98
|
+
);
|
|
99
|
+
if (breadcrumbLinks.length === 0) {
|
|
100
|
+
cy.log("No clickable breadcrumb link for this org unit — skipping.");
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
cy.wrap(breadcrumbLinks.first())
|
|
104
|
+
.should("have.attr", "href")
|
|
105
|
+
.and("match", new RegExp(`^/${LOCALE_UNDER_TEST}(/|$)`));
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("keeps the locale prefix on the Org Unit Details navbar 'Start shopping' link and the hierarchy tree links, consistently with the main Navbar", () => {
|
|
111
|
+
isLocalizationEnabledInThisEnvironment().then((enabled) => {
|
|
112
|
+
if (!enabled) {
|
|
113
|
+
cy.log(
|
|
114
|
+
`Localization not enabled for locale "${LOCALE_UNDER_TEST}" in this environment — skipping.`
|
|
115
|
+
);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
cy.contains("Organizational Units").click();
|
|
120
|
+
|
|
121
|
+
cy.get("[data-fs-hierarchy-tree-wrapper]", {
|
|
122
|
+
timeout: TEST_CONFIG.TIMEOUTS.LONG_DELAY,
|
|
123
|
+
}).should("exist");
|
|
124
|
+
|
|
125
|
+
useInternalSearch(TEST_DATA.ORG_UNITS.CHILD_1);
|
|
126
|
+
|
|
127
|
+
// The hierarchy tree's search results are fetched and rendered client-side, which
|
|
128
|
+
// can hit the already-flagged SPA/client-render locale-sync finding (separate from
|
|
129
|
+
// this plugin's `resolveLink` usage, itself proven correct via SSR). Log instead of
|
|
130
|
+
// hard-failing on this specific link so it doesn't mask the click-through below.
|
|
131
|
+
cy.get("[data-fs-org-unit-item-name]")
|
|
132
|
+
.contains(TEST_DATA.ORG_UNITS.CHILD_1)
|
|
133
|
+
.parents("[data-fs-org-unit-item]")
|
|
134
|
+
.find("[data-fs-org-unit-item-click-area]")
|
|
135
|
+
.invoke("attr", "href")
|
|
136
|
+
.then((href) => {
|
|
137
|
+
if (!href?.startsWith(`/${LOCALE_UNDER_TEST}`)) {
|
|
138
|
+
cy.log(
|
|
139
|
+
`Hierarchy tree link "${href}" lost the locale prefix (known client-render finding) — continuing.`
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
cy.get("[data-fs-org-unit-item-name]")
|
|
145
|
+
.contains(TEST_DATA.ORG_UNITS.CHILD_1)
|
|
146
|
+
.parents("[data-fs-org-unit-item]")
|
|
147
|
+
.find("[data-fs-org-unit-item-click-area]")
|
|
148
|
+
.click();
|
|
149
|
+
|
|
150
|
+
cy.get("[data-fs-bp-org-unit-details-navbar]", {
|
|
151
|
+
timeout: TEST_CONFIG.TIMEOUTS.PAGE_LOAD,
|
|
152
|
+
}).should("be.visible");
|
|
153
|
+
|
|
154
|
+
reloadUnderLocale();
|
|
155
|
+
|
|
156
|
+
cy.get("[data-fs-bp-org-unit-details-navbar-start-shopping-link]")
|
|
157
|
+
.should("have.attr", "href")
|
|
158
|
+
.and("match", new RegExp(`^/${LOCALE_UNDER_TEST}(/|$)`));
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("shows the locale selector (globe) in both the main Navbar and the Org Unit Details navbar, with non-empty labels and no crash on missing CMS keys", () => {
|
|
163
|
+
isLocalizationEnabledInThisEnvironment().then((enabled) => {
|
|
164
|
+
if (!enabled) {
|
|
165
|
+
cy.log(
|
|
166
|
+
`Localization not enabled for locale "${LOCALE_UNDER_TEST}" in this environment — skipping.`
|
|
167
|
+
);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
cy.contains("Profile").click();
|
|
172
|
+
|
|
173
|
+
cy.get("[data-fs-localization-button]").should("be.visible").click();
|
|
174
|
+
|
|
175
|
+
// Whether or not the `shared` CMS entry already has these keys populated, `t()`
|
|
176
|
+
// must never crash and must never render blank text (fallback = key itself).
|
|
177
|
+
cy.get("[data-fs-localization-selector-content]")
|
|
178
|
+
.should("be.visible")
|
|
179
|
+
.invoke("text")
|
|
180
|
+
.should("not.be.empty");
|
|
181
|
+
assertNoRawCmsKeysOrPlaceholders(
|
|
182
|
+
"[data-fs-localization-selector-content]"
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
// No blank page / crash after opening the selector.
|
|
186
|
+
cy.get("[data-fs-bp-nav]").should("be.visible");
|
|
187
|
+
|
|
188
|
+
// Close the selector (its overlay can otherwise block later clicks) and start
|
|
189
|
+
// from a fresh home visit — top-level nav links are only reachable from the
|
|
190
|
+
// home page's sidebar, not from within an already-open tabbed page.
|
|
191
|
+
cy.get("body").type("{esc}");
|
|
192
|
+
cy.get("[data-fs-overlay]", {
|
|
193
|
+
timeout: TEST_CONFIG.TIMEOUTS.PAGE_LOAD,
|
|
194
|
+
}).should("not.exist");
|
|
195
|
+
|
|
196
|
+
// Same check on the Org Unit Details navbar.
|
|
197
|
+
visitFreshUnderLocale(TEST_CONFIG.ROUTES.BUYER_PORTAL);
|
|
198
|
+
cy.contains("Organizational Units").click();
|
|
199
|
+
cy.get("[data-fs-hierarchy-tree-wrapper]", {
|
|
200
|
+
timeout: TEST_CONFIG.TIMEOUTS.LONG_DELAY,
|
|
201
|
+
}).should("exist");
|
|
202
|
+
useInternalSearch(TEST_DATA.ORG_UNITS.CHILD_1);
|
|
203
|
+
cy.get("[data-fs-org-unit-item-name]")
|
|
204
|
+
.contains(TEST_DATA.ORG_UNITS.CHILD_1)
|
|
205
|
+
.parents("[data-fs-org-unit-item]")
|
|
206
|
+
.find("[data-fs-org-unit-item-click-area]")
|
|
207
|
+
.click();
|
|
208
|
+
cy.get("[data-fs-bp-org-unit-details-navbar]", {
|
|
209
|
+
timeout: TEST_CONFIG.TIMEOUTS.PAGE_LOAD,
|
|
210
|
+
}).should("be.visible");
|
|
211
|
+
cy.get(
|
|
212
|
+
"[data-fs-bp-org-unit-details-navbar] [data-fs-localization-button]"
|
|
213
|
+
).should("be.visible");
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it("persists the selected locale across a browser reload", () => {
|
|
218
|
+
// KNOWN BUG (found while writing this test, confirmed via a plain `curl`, no
|
|
219
|
+
// client JS involved): `GET /pt-BR/pvt/organization-account` returns a 302 whose
|
|
220
|
+
// `Location` header points to `/pvt/organization-account/org-unit/{id}` WITHOUT
|
|
221
|
+
// the `/pt-BR` prefix, so the redirect target renders `lang="en-US"`. This is a
|
|
222
|
+
// server-side redirect issue (unrelated to `resolveLink`/client navigation), and
|
|
223
|
+
// is expected to keep this assertion red until fixed.
|
|
224
|
+
isLocalizationEnabledInThisEnvironment().then((enabled) => {
|
|
225
|
+
if (!enabled) {
|
|
226
|
+
cy.log(
|
|
227
|
+
`Localization not enabled for locale "${LOCALE_UNDER_TEST}" in this environment — skipping.`
|
|
228
|
+
);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
cy.get("html").should("have.attr", "lang", LOCALE_UNDER_TEST);
|
|
233
|
+
|
|
234
|
+
// A plain reload of the same URL must keep reflecting the locale.
|
|
235
|
+
cy.reload();
|
|
236
|
+
|
|
237
|
+
cy.get("html").should("have.attr", "lang", LOCALE_UNDER_TEST);
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("does not break the Navbar layout on mobile/tablet viewports", () => {
|
|
242
|
+
isLocalizationEnabledInThisEnvironment().then((enabled) => {
|
|
243
|
+
if (!enabled) {
|
|
244
|
+
cy.log(
|
|
245
|
+
`Localization not enabled for locale "${LOCALE_UNDER_TEST}" in this environment — skipping.`
|
|
246
|
+
);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
cy.contains("Profile").click();
|
|
251
|
+
|
|
252
|
+
(
|
|
253
|
+
[
|
|
254
|
+
[375, 667],
|
|
255
|
+
[768, 1024],
|
|
256
|
+
] as const
|
|
257
|
+
).forEach(([width, height]) => {
|
|
258
|
+
cy.viewport(width, height);
|
|
259
|
+
cy.get("[data-fs-localization-button]").should("be.visible");
|
|
260
|
+
cy.get("[data-fs-bp-nav]").then(($nav) => {
|
|
261
|
+
expect($nav[0].scrollWidth).to.be.at.most(
|
|
262
|
+
$nav[0].parentElement?.clientWidth
|
|
263
|
+
? $nav[0].parentElement.clientWidth + 1
|
|
264
|
+
: width + 1
|
|
265
|
+
);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// Reset to the default viewport so later tests in this spec aren't affected.
|
|
270
|
+
cy.viewport(
|
|
271
|
+
Cypress.config("viewportWidth"),
|
|
272
|
+
Cypress.config("viewportHeight")
|
|
273
|
+
);
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it("does not fire localization requests from the client — SSR/loader only", () => {
|
|
278
|
+
cy.intercept("GET", "**/api/content-platform/data/vtex/b2b/**").as(
|
|
279
|
+
"localizationRequest"
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
cy.visit(TEST_CONFIG.ROUTES.BUYER_PORTAL);
|
|
283
|
+
cy.get("[data-fs-vertical-nav-menu-item]").should("exist");
|
|
284
|
+
|
|
285
|
+
cy.contains("Profile").click();
|
|
286
|
+
cy.get("[data-fs-bp-profile]").should("exist");
|
|
287
|
+
|
|
288
|
+
// Top-level nav links are only reachable from the home page's sidebar, not from
|
|
289
|
+
// within an already-open tabbed page — go back to home for the second page.
|
|
290
|
+
cy.visit(TEST_CONFIG.ROUTES.BUYER_PORTAL);
|
|
291
|
+
cy.contains("Organizational Units").click();
|
|
292
|
+
cy.get("[data-fs-bp-nav]").should("be.visible");
|
|
293
|
+
|
|
294
|
+
cy.get("@localizationRequest.all").should("have.length", 0);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it("shows translated error text, not a raw CMS key, when a client-side error occurs", () => {
|
|
298
|
+
// Deliberately reproduces the client-side error found while validating this ticket
|
|
299
|
+
// (visiting a locale-prefixed page with a stale, different-channel session cookie)
|
|
300
|
+
// to confirm the Error component's fallback text is translated, per the checklist's
|
|
301
|
+
// "loader/runtime error shows translated text" requirement.
|
|
302
|
+
isLocalizationEnabledInThisEnvironment().then((enabled) => {
|
|
303
|
+
if (!enabled) {
|
|
304
|
+
cy.log(
|
|
305
|
+
`Localization not enabled for locale "${LOCALE_UNDER_TEST}" in this environment — skipping.`
|
|
306
|
+
);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
cy.get("[data-fs-vertical-nav-menu-item]")
|
|
311
|
+
.contains("Assortments")
|
|
312
|
+
.click({ timeout: TEST_CONFIG.TIMEOUTS.PAGE_LOAD });
|
|
313
|
+
|
|
314
|
+
cy.get("body").then(($body) => {
|
|
315
|
+
if ($body.find("[data-fs-bp-header-inside-title]").length === 0) {
|
|
316
|
+
cy.log(
|
|
317
|
+
"Did not land on the Assortments page this run (known client-side SPA-navigation finding) — skipping."
|
|
318
|
+
);
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
cy.location("pathname").then((path) => {
|
|
323
|
+
// Re-visit the SAME path (default locale, same channel) WITHOUT clearing
|
|
324
|
+
// cookies twice in a row from two different locale contexts, to reliably land
|
|
325
|
+
// the client-side session/channel conflict on the Assortments page.
|
|
326
|
+
cy.visit(`/${LOCALE_UNDER_TEST}${path}`, { failOnStatusCode: false });
|
|
327
|
+
cy.visit(path, { failOnStatusCode: false });
|
|
328
|
+
cy.visit(`/${LOCALE_UNDER_TEST}${path}`, { failOnStatusCode: false });
|
|
329
|
+
|
|
330
|
+
cy.get("body").then(($body2) => {
|
|
331
|
+
if ($body2.find("[data-fs-bp-error]").length === 0) {
|
|
332
|
+
cy.log(
|
|
333
|
+
"Client-side error did not reproduce this run (known intermittent finding) — skipping."
|
|
334
|
+
);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
cy.get("[data-fs-bp-error-title]")
|
|
338
|
+
.should("be.visible")
|
|
339
|
+
.invoke("text")
|
|
340
|
+
.should("not.be.empty");
|
|
341
|
+
assertNoRawCmsKeysOrPlaceholders("[data-fs-bp-error]");
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
it("renders pagination counters with real numbers, not raw interpolation placeholders", () => {
|
|
349
|
+
cy.visit(TEST_CONFIG.ROUTES.BUYER_PORTAL);
|
|
350
|
+
cy.contains("Organizational Units").click();
|
|
351
|
+
cy.get("[data-fs-hierarchy-tree-wrapper]", {
|
|
352
|
+
timeout: TEST_CONFIG.TIMEOUTS.LONG_DELAY,
|
|
353
|
+
}).should("exist");
|
|
354
|
+
|
|
355
|
+
cy.get("body").then(($body) => {
|
|
356
|
+
const counter = $body.find("[data-fs-bp-paginator-counter]");
|
|
357
|
+
if (counter.length === 0) {
|
|
358
|
+
cy.log("No paginator rendered on this page — skipping.");
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
cy.wrap(counter.first())
|
|
362
|
+
.invoke("text")
|
|
363
|
+
.should("match", /\d/)
|
|
364
|
+
.and("not.match", RAW_PLACEHOLDER_PATTERN);
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it("does not leak raw CMS keys in the sidebar, About drawer, or locale selector", () => {
|
|
369
|
+
isLocalizationEnabledInThisEnvironment().then((enabled) => {
|
|
370
|
+
if (!enabled) {
|
|
371
|
+
cy.log(
|
|
372
|
+
`Localization not enabled for locale "${LOCALE_UNDER_TEST}" in this environment — skipping.`
|
|
373
|
+
);
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
cy.contains("Profile").click();
|
|
378
|
+
|
|
379
|
+
cy.get("[data-fs-bp-sidebar-drawer-btn]").click();
|
|
380
|
+
cy.get("body").then(($body) => {
|
|
381
|
+
const sidebar = $body.find(
|
|
382
|
+
"[data-fs-bp-org-unit-details-navbar-link], [data-fs-org-units-hierarchy], nav [data-fs-vertical-nav]"
|
|
383
|
+
);
|
|
384
|
+
if (sidebar.length > 0) {
|
|
385
|
+
assertNoRawCmsKeysOrPlaceholders(
|
|
386
|
+
"[data-fs-bp-org-unit-details-navbar-link], [data-fs-org-units-hierarchy], nav [data-fs-vertical-nav]"
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
// Close the sidebar drawer before continuing (best-effort; ignore if already closed).
|
|
391
|
+
cy.get("body").type("{esc}");
|
|
392
|
+
|
|
393
|
+
cy.get("[data-fs-bp-nav-about-trigger]").click();
|
|
394
|
+
cy.get("[data-fs-bp-about-information]", {
|
|
395
|
+
timeout: TEST_CONFIG.TIMEOUTS.PAGE_LOAD,
|
|
396
|
+
}).should("be.visible");
|
|
397
|
+
assertNoRawCmsKeysOrPlaceholders("[data-fs-bp-about-information]");
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
it("interpolates the actual user name into a real link (not a raw placeholder) in the Delete User confirmation message", () => {
|
|
402
|
+
cy.visit(TEST_CONFIG.ROUTES.BUYER_PORTAL);
|
|
403
|
+
cy.contains("Users").click();
|
|
404
|
+
cy.get("[data-fs-users-section]", {
|
|
405
|
+
timeout: TEST_CONFIG.TIMEOUTS.LONG_DELAY,
|
|
406
|
+
}).should("exist");
|
|
407
|
+
|
|
408
|
+
// Use whichever user happens to be first in the list — this test only exercises
|
|
409
|
+
// the confirmation drawer's interpolation and cancels out, it never deletes anyone,
|
|
410
|
+
// so it doesn't depend on any specific seeded user or table column order.
|
|
411
|
+
cy.get("[data-fs-bp-table-row]")
|
|
412
|
+
.first()
|
|
413
|
+
.within(() => {
|
|
414
|
+
cy.get("[data-fs-bp-basic-dropdown-menu-trigger]").click();
|
|
415
|
+
});
|
|
416
|
+
cy.contains("Delete").click();
|
|
417
|
+
|
|
418
|
+
cy.get("[data-fs-bp-delete-user-drawer]").should("be.visible");
|
|
419
|
+
cy.get("[data-fs-bp-delete-user-drawer-user-name]")
|
|
420
|
+
.should("be.visible")
|
|
421
|
+
.and("have.attr", "href")
|
|
422
|
+
.and("not.be.empty");
|
|
423
|
+
cy.get("[data-fs-bp-delete-user-drawer-user-name]")
|
|
424
|
+
.invoke("text")
|
|
425
|
+
.should("not.be.empty");
|
|
426
|
+
assertNoRawCmsKeysOrPlaceholders("[data-fs-bp-delete-user-drawer-body]");
|
|
427
|
+
|
|
428
|
+
// Cancel — this test only validates the interpolation, it must not delete the user.
|
|
429
|
+
cy.get("[data-fs-bp-delete-user-drawer]")
|
|
430
|
+
.contains("button", "Cancel")
|
|
431
|
+
.click();
|
|
432
|
+
cy.get("[data-fs-bp-delete-user-drawer]").should("not.exist");
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it("renders actual CMS-translated content, not just a preserved URL prefix (Assortments page title)", () => {
|
|
436
|
+
// The Assortments page is the one page with real pt-BR/en-US CMS entries today
|
|
437
|
+
// (per B2BTEAM-3709), so it's the only reliable place to assert that *content*,
|
|
438
|
+
// not just routing, changes with the locale.
|
|
439
|
+
cy.visit(TEST_CONFIG.ROUTES.BUYER_PORTAL);
|
|
440
|
+
cy.get("[data-fs-vertical-nav-menu-item]")
|
|
441
|
+
.contains("Assortments")
|
|
442
|
+
.click({ timeout: TEST_CONFIG.TIMEOUTS.PAGE_LOAD });
|
|
443
|
+
|
|
444
|
+
cy.get("[data-fs-bp-header-inside-title]", {
|
|
445
|
+
timeout: TEST_CONFIG.TIMEOUTS.PAGE_LOAD,
|
|
446
|
+
}).should("be.visible");
|
|
447
|
+
|
|
448
|
+
cy.get("html").invoke("attr", "lang").as("defaultLocaleLangAttr");
|
|
449
|
+
cy.get("[data-fs-bp-header-inside-title]")
|
|
450
|
+
.invoke("text")
|
|
451
|
+
.as("defaultLocaleTitle");
|
|
452
|
+
|
|
453
|
+
cy.location("pathname").then((defaultLocalePath) => {
|
|
454
|
+
visitFreshUnderLocale(defaultLocalePath);
|
|
455
|
+
|
|
456
|
+
cy.get("body").then(($body) => {
|
|
457
|
+
if ($body.find("[data-fs-bp-header-inside-title]").length === 0) {
|
|
458
|
+
cy.log(
|
|
459
|
+
`Localization not enabled for locale "${LOCALE_UNDER_TEST}" in this environment — skipping.`
|
|
460
|
+
);
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
cy.get("html")
|
|
465
|
+
.should("have.attr", "lang", LOCALE_UNDER_TEST)
|
|
466
|
+
.then(function () {
|
|
467
|
+
expect(LOCALE_UNDER_TEST).to.not.equal(this.defaultLocaleLangAttr);
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
cy.get("[data-fs-bp-header-inside-title]")
|
|
471
|
+
.invoke("text")
|
|
472
|
+
.should("not.be.empty")
|
|
473
|
+
.then(function (translatedTitle) {
|
|
474
|
+
expect(
|
|
475
|
+
translatedTitle,
|
|
476
|
+
"page title should be translated, not the same text as the default locale"
|
|
477
|
+
).to.not.equal(this.defaultLocaleTitle);
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
});
|
|
482
|
+
});
|
|
@@ -2,6 +2,14 @@ import { TEST_CONFIG } from "../constants";
|
|
|
2
2
|
|
|
3
3
|
Cypress.Commands.add("login", () => {
|
|
4
4
|
cy.session("organization-account-login", () => {
|
|
5
|
+
const authToken = Cypress.env("VTEX_AUTH_TOKEN");
|
|
6
|
+
|
|
7
|
+
if (authToken) {
|
|
8
|
+
cy.visit(TEST_CONFIG.LOCAL_URL);
|
|
9
|
+
cy.setCookie(TEST_CONFIG.AUTH.COOKIE_NAME, authToken);
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
5
13
|
const loginOrigin = new URL(TEST_CONFIG.AUTH.LOGIN_URL).origin;
|
|
6
14
|
const login = Cypress.env("VTEX_ACCOUNT_LOGIN");
|
|
7
15
|
const password = Cypress.env("VTEX_ACCOUNT_PASSWORD");
|