@shopware-ag/acceptance-test-suite 12.22.1 → 12.23.0

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/dist/index.mjs CHANGED
@@ -1113,7 +1113,7 @@ const common$b = {
1113
1113
  const listing$n = {
1114
1114
  addNewSet: "Add new set"
1115
1115
  };
1116
- const create$d = {
1116
+ const create$e = {
1117
1117
  assignTo: "Assign To",
1118
1118
  save: "Save",
1119
1119
  cancel: "Cancel"
@@ -1145,7 +1145,7 @@ const dialogs$7 = {
1145
1145
  const administrationCustomField = {
1146
1146
  common: common$b,
1147
1147
  listing: listing$n,
1148
- create: create$d,
1148
+ create: create$e,
1149
1149
  detail: detail$n,
1150
1150
  general: general$9,
1151
1151
  actions: actions$g,
@@ -1206,7 +1206,7 @@ const administrationDocument = {
1206
1206
  detail: detail$m
1207
1207
  };
1208
1208
 
1209
- const create$c = {
1209
+ const create$d = {
1210
1210
  searchLayoutsPlaceholder: "Search layouts...",
1211
1211
  assignLayout: "Assign layout",
1212
1212
  createNewLayout: "Create new layout",
@@ -1225,7 +1225,7 @@ const layout$1 = {
1225
1225
  editInDesigner: "Edit in designer"
1226
1226
  };
1227
1227
  const administrationLandingPage = {
1228
- create: create$c,
1228
+ create: create$d,
1229
1229
  general: general$8,
1230
1230
  layout: layout$1
1231
1231
  };
@@ -1233,7 +1233,7 @@ const administrationLandingPage = {
1233
1233
  const listing$l = {
1234
1234
  createNewLayout: "Create new layout"
1235
1235
  };
1236
- const create$b = {
1236
+ const create$c = {
1237
1237
  shopPage: "Shop page",
1238
1238
  landingPage: "Landing page",
1239
1239
  listingPage: "Listing page",
@@ -1255,7 +1255,7 @@ const detail$l = {
1255
1255
  };
1256
1256
  const administrationLayout = {
1257
1257
  listing: listing$l,
1258
- create: create$b,
1258
+ create: create$c,
1259
1259
  detail: detail$l
1260
1260
  };
1261
1261
 
@@ -1276,7 +1276,7 @@ const listing$k = {
1276
1276
  testFlow: "Test flow",
1277
1277
  flowTemplates: "Flow templates"
1278
1278
  };
1279
- const create$a = {
1279
+ const create$b = {
1280
1280
  addAction: "Add action",
1281
1281
  addConditionIf: "Add condition (IF)",
1282
1282
  addActionThen: "Add action (THEN)",
@@ -1299,7 +1299,7 @@ const messages$6 = {
1299
1299
  };
1300
1300
  const administrationFlowBuilder = {
1301
1301
  listing: listing$k,
1302
- create: create$a,
1302
+ create: create$b,
1303
1303
  detail: detail$k,
1304
1304
  templates: templates$1,
1305
1305
  messages: messages$6
@@ -1334,7 +1334,7 @@ const administrationDashboard = {
1334
1334
  const listing$j = {
1335
1335
  addManufacturer: "Add manufacturer"
1336
1336
  };
1337
- const create$9 = {
1337
+ const create$a = {
1338
1338
  name: "Name",
1339
1339
  website: "Website",
1340
1340
  save: "Save",
@@ -1353,7 +1353,7 @@ const dialogs$6 = {
1353
1353
  };
1354
1354
  const administrationManufacturer = {
1355
1355
  listing: listing$j,
1356
- create: create$9,
1356
+ create: create$a,
1357
1357
  detail: detail$j,
1358
1358
  actions: actions$f,
1359
1359
  dialogs: dialogs$6
@@ -1612,7 +1612,7 @@ const listing$g = {
1612
1612
  const detail$f = {
1613
1613
  technicalUrl: "Technical URL"
1614
1614
  };
1615
- const create$8 = {
1615
+ const create$9 = {
1616
1616
  title: "New customer group",
1617
1617
  cardTitle: "Customer group",
1618
1618
  save: "Save",
@@ -1624,7 +1624,7 @@ const create$8 = {
1624
1624
  const administrationCustomerGroup = {
1625
1625
  listing: listing$g,
1626
1626
  detail: detail$f,
1627
- create: create$8
1627
+ create: create$9
1628
1628
  };
1629
1629
 
1630
1630
  const welcome$1 = {
@@ -1720,7 +1720,16 @@ const detail$e = {
1720
1720
  colorProperty: "Color",
1721
1721
  sizeProperty: "Size",
1722
1722
  stockPlaceholder: "Enter quantity in stock...",
1723
- restockTimePlaceholder: "Enter restock time in days..."
1723
+ restockTimePlaceholder: "Enter restock time in days...",
1724
+ name: "Name",
1725
+ productNumber: "Product number",
1726
+ stock: "Stock",
1727
+ copySuffix: "Copy",
1728
+ width: "Width",
1729
+ height: "Height",
1730
+ length: "Length",
1731
+ weight: "Weight",
1732
+ description: "Description"
1724
1733
  };
1725
1734
  const variants$1 = {
1726
1735
  properties: "Properties"
@@ -1737,8 +1746,11 @@ const bulkEdit$2 = {
1737
1746
  close: "Close"
1738
1747
  };
1739
1748
  const listing$f = {
1749
+ addProduct: "Add product",
1740
1750
  bulkEdit: "Bulk edit",
1741
- startBulkEdit: "Start bulk edit"
1751
+ startBulkEdit: "Start bulk edit",
1752
+ addDigitalProduct: "Add digital product",
1753
+ digitalIndicator: "digital"
1742
1754
  };
1743
1755
  const tabs$7 = {
1744
1756
  specifications: "Specifications",
@@ -1754,7 +1766,10 @@ const buttons$b = {
1754
1766
  uploadFile: "Upload file",
1755
1767
  generateVariants: "Generate variants",
1756
1768
  next: "Next",
1757
- saveVariants: "Save variants"
1769
+ saveVariants: "Save variants",
1770
+ cancel: "Cancel",
1771
+ saveAndDuplicate: "Save and duplicate",
1772
+ "delete": "Delete"
1758
1773
  };
1759
1774
  const modals$2 = {
1760
1775
  generateVariants: "Generate variants"
@@ -1767,6 +1782,9 @@ const propertyValues$1 = {
1767
1782
  medium: "Medium",
1768
1783
  large: "Large"
1769
1784
  };
1785
+ const create$8 = {
1786
+ title: "New product"
1787
+ };
1770
1788
  const administrationProduct = {
1771
1789
  detail: detail$e,
1772
1790
  variants: variants$1,
@@ -1777,7 +1795,8 @@ const administrationProduct = {
1777
1795
  tabs: tabs$7,
1778
1796
  buttons: buttons$b,
1779
1797
  modals: modals$2,
1780
- propertyValues: propertyValues$1
1798
+ propertyValues: propertyValues$1,
1799
+ create: create$8
1781
1800
  };
1782
1801
 
1783
1802
  const tabs$6 = {
@@ -2765,9 +2784,11 @@ const deAdministrationPayment = {
2765
2784
  };
2766
2785
 
2767
2786
  const listing$4 = {
2768
- addProduct: "Produkt hinzufügen",
2787
+ addProduct: "Produkt anlegen",
2769
2788
  bulkEdit: "Massenbearbeitung",
2770
- startBulkEdit: "Bearbeiten"
2789
+ startBulkEdit: "Bearbeiten",
2790
+ addDigitalProduct: "Digitales Produkt anlegen",
2791
+ digitalIndicator: "digital"
2771
2792
  };
2772
2793
  const create$1 = {
2773
2794
  title: "Neues Produkt",
@@ -2786,7 +2807,12 @@ const detail$3 = {
2786
2807
  colorProperty: "Color",
2787
2808
  sizeProperty: "Size",
2788
2809
  stockPlaceholder: "Gib den Lagerbestand ein ...",
2789
- restockTimePlaceholder: "Lagerbestand"
2810
+ restockTimePlaceholder: "Lagerbestand",
2811
+ copySuffix: "Kopie",
2812
+ width: "Breite",
2813
+ height: "Höhe",
2814
+ length: "Länge",
2815
+ weight: "Gewicht"
2790
2816
  };
2791
2817
  const errors$1 = {
2792
2818
  flows: {
@@ -2819,7 +2845,10 @@ const buttons$5 = {
2819
2845
  uploadFile: "Hochladen",
2820
2846
  generateVariants: "Generate variants",
2821
2847
  next: "Weiter",
2822
- saveVariants: "Speichern"
2848
+ saveVariants: "Speichern",
2849
+ cancel: "Abbrechen",
2850
+ saveAndDuplicate: "Speichern und duplizieren",
2851
+ "delete": "Löschen"
2823
2852
  };
2824
2853
  const modals$1 = {
2825
2854
  generateVariants: "Generate variants"
@@ -8581,6 +8610,9 @@ async function getCustomFieldCardLocators(page, customFieldSetName, customFieldN
8581
8610
  };
8582
8611
  }
8583
8612
 
8613
+ function fieldName$1(label) {
8614
+ return new RegExp(`^${label.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*\\*?$`);
8615
+ }
8584
8616
  class ProductDetail {
8585
8617
  contentView;
8586
8618
  productHeadline;
@@ -8590,9 +8622,17 @@ class ProductDetail {
8590
8622
  savePhysicalProductButton;
8591
8623
  saveButtonLoadingSpinner;
8592
8624
  saveButtonCheckMark;
8625
+ /**
8626
+ * "Save and duplicate" is only reachable through the split button next to "Save".
8627
+ */
8628
+ saveContextMenuButton;
8629
+ saveAndDuplicateButton;
8593
8630
  /**
8594
8631
  * General Info
8595
8632
  */
8633
+ nameInput;
8634
+ productNumberInput;
8635
+ descriptionEditor;
8596
8636
  manufacturerDropdownText;
8597
8637
  /**
8598
8638
  * Prices
@@ -8609,6 +8649,13 @@ class ProductDetail {
8609
8649
  activeForAllSalesChannelsToggle;
8610
8650
  tagsInput;
8611
8651
  saleChannelsInput;
8652
+ saleChannelsSearchInput;
8653
+ selectedSaleChannel;
8654
+ categoriesInput;
8655
+ categoriesSearchInput;
8656
+ selectedCategory;
8657
+ categorySearchResult;
8658
+ saleChannelSearchResult;
8612
8659
  /**
8613
8660
  * Labelling
8614
8661
  */
@@ -8616,9 +8663,16 @@ class ProductDetail {
8616
8663
  /**
8617
8664
  * Media Upload interactions
8618
8665
  */
8666
+ mediaCard;
8619
8667
  uploadMediaButton;
8620
8668
  coverImage;
8621
8669
  productImage;
8670
+ /**
8671
+ * Files of a digital product
8672
+ */
8673
+ downloadsCard;
8674
+ uploadDownloadFileButton;
8675
+ downloadFileName;
8622
8676
  /**
8623
8677
  * Tabs
8624
8678
  */
@@ -8664,6 +8718,14 @@ class ProductDetail {
8664
8718
  * Cards
8665
8719
  */
8666
8720
  customFieldCard;
8721
+ /**
8722
+ * Specifications tab, product measurements
8723
+ */
8724
+ measurementCard;
8725
+ widthInput;
8726
+ heightInput;
8727
+ lengthInput;
8728
+ weightInput;
8667
8729
  page;
8668
8730
  instanceMeta;
8669
8731
  constructor(page, instanceMeta) {
@@ -8671,59 +8733,131 @@ class ProductDetail {
8671
8733
  this.instanceMeta = instanceMeta;
8672
8734
  this.contentView = page.locator(".sw-desktop__content");
8673
8735
  this.productHeadline = page.locator(".smart-bar__header");
8674
- this.savePhysicalProductButton = page.getByRole("button", { name: translate("administration:product:buttons.save") });
8736
+ this.savePhysicalProductButton = page.getByRole("button", {
8737
+ name: translate("administration:product:buttons.save")
8738
+ });
8675
8739
  this.saveButtonCheckMark = page.locator(".icon--regular-checkmark-xs");
8676
8740
  this.saveButtonLoadingSpinner = page.locator("sw-loader");
8677
- this.specificationsTabLink = page.getByRole("tab", { name: translate("administration:product:tabs.specifications") });
8678
- this.advancedPricingTabLink = page.getByRole("tab", { name: translate("administration:product:tabs.advancedPricing") });
8679
- this.variantsTabLink = page.getByRole("tab", { name: translate("administration:product:tabs.variants") });
8680
- this.layoutTabLink = page.getByRole("tab", { name: translate("administration:product:tabs.layout") });
8681
- this.crossSellingTabLink = page.getByRole("tab", { name: translate("administration:product:tabs.crossSelling") });
8682
- this.SEOTabLink = page.getByRole("tab", { name: translate("administration:product:tabs.seo") });
8683
- this.reviewsTabLink = page.getByRole("tab", { name: translate("administration:product:tabs.reviews") });
8741
+ this.saveContextMenuButton = page.locator(".sw-product-detail__button-context-menu");
8742
+ this.saveAndDuplicateButton = page.locator(".sw-product-detail__save-duplicate-action");
8743
+ this.specificationsTabLink = page.getByRole("tab", {
8744
+ name: translate("administration:product:tabs.specifications")
8745
+ });
8746
+ this.advancedPricingTabLink = page.getByRole("tab", {
8747
+ name: translate("administration:product:tabs.advancedPricing")
8748
+ });
8749
+ this.variantsTabLink = page.getByRole("tab", {
8750
+ name: translate("administration:product:tabs.variants")
8751
+ });
8752
+ this.layoutTabLink = page.getByRole("tab", {
8753
+ name: translate("administration:product:tabs.layout")
8754
+ });
8755
+ this.crossSellingTabLink = page.getByRole("tab", {
8756
+ name: translate("administration:product:tabs.crossSelling")
8757
+ });
8758
+ this.SEOTabLink = page.getByRole("tab", {
8759
+ name: translate("administration:product:tabs.seo")
8760
+ });
8761
+ this.reviewsTabLink = page.getByRole("tab", {
8762
+ name: translate("administration:product:tabs.reviews")
8763
+ });
8764
+ this.nameInput = page.getByRole("textbox", {
8765
+ name: fieldName$1(translate("administration:product:detail.name"))
8766
+ });
8767
+ this.productNumberInput = page.getByRole("textbox", {
8768
+ name: fieldName$1(translate("administration:product:detail.productNumber"))
8769
+ });
8684
8770
  this.manufacturerDropdownText = page.locator(".sw-select-product__select_manufacturer");
8771
+ this.descriptionEditor = instanceMeta.features["METEOR_TEXT_EDITOR"] ?? satisfies(instanceMeta.version, ">=6.8") ? page.locator(".mt-text-editor__content-editor") : page.locator(".sw-text-editor__content-editor");
8685
8772
  this.priceGrossInput = page.locator("#sw-price-field-gross").first();
8686
8773
  this.stockInput = page.getByPlaceholder(translate("administration:product:detail.stockPlaceholder"));
8687
8774
  this.restockTimeInput = page.getByPlaceholder(translate("administration:product:detail.restockTimePlaceholder"));
8688
8775
  this.activeForAllSalesChannelsToggle = page.locator(".sw-field--product-active").getByRole("checkbox");
8689
8776
  this.tagsInput = page.locator(".sw-product-category-form__tag-field");
8690
8777
  this.saleChannelsInput = page.locator(".sw-product-detail__select-visibility");
8778
+ this.saleChannelsSearchInput = this.saleChannelsInput.locator(".sw-select-selection-list__input");
8779
+ this.selectedSaleChannel = this.saleChannelsInput.locator(".sw-select-selection-list__item-holder");
8780
+ this.categoriesInput = page.locator(".sw-product-detail__select-category");
8781
+ this.categoriesSearchInput = this.categoriesInput.locator(".sw-category-tree__input-field");
8782
+ this.selectedCategory = page.locator(".sw-category-tree-field__selected-label");
8783
+ this.categorySearchResult = (categoryName) => page.locator(".sw-category-tree-field__search-result").filter({ hasText: categoryName });
8784
+ this.saleChannelSearchResult = (salesChannelName) => page.locator(".sw-select-result").filter({ hasText: salesChannelName });
8691
8785
  if (satisfies(instanceMeta.version, "<6.7")) {
8692
8786
  this.releaseDateInput = page.locator(".sw-product-detail-base__labelling-card").locator(".form-control");
8693
8787
  } else {
8694
8788
  this.releaseDateInput = page.locator(".dp__input");
8695
8789
  }
8696
- this.uploadMediaButton = page.getByRole("button", { name: translate("administration:product:buttons.uploadFile") });
8790
+ this.mediaCard = page.locator(".sw-product-detail-base__media");
8791
+ this.uploadMediaButton = this.mediaCard.getByRole("button", {
8792
+ name: translate("administration:product:buttons.uploadFile")
8793
+ });
8697
8794
  this.coverImage = page.locator(".sw-product-media-form__cover-image");
8698
8795
  this.productImage = page.locator(".sw-media-preview-v2__item");
8699
- this.generateVariantsButton = page.getByRole("button", { name: translate("administration:product:buttons.generateVariants") });
8700
- this.variantsModal = page.getByRole("dialog", { name: translate("administration:product:modals.generateVariants") });
8701
- this.variantsModalHeadline = this.variantsModal.getByRole("heading", { name: translate("administration:product:modals.generateVariants") });
8702
- this.variantsNextButton = this.variantsModal.getByRole("button", { name: translate("administration:product:buttons.next"), exact: true });
8703
- this.variantsSaveButton = this.variantsModal.getByRole("button", { name: translate("administration:product:buttons.saveVariants") });
8796
+ this.downloadsCard = page.locator(".sw-product-detail-base__downloads");
8797
+ this.uploadDownloadFileButton = this.downloadsCard.getByRole("button", {
8798
+ name: translate("administration:product:buttons.uploadFile")
8799
+ });
8800
+ this.downloadFileName = this.downloadsCard.locator(".sw-product-download-form-row__name");
8801
+ this.generateVariantsButton = page.getByRole("button", {
8802
+ name: translate("administration:product:buttons.generateVariants")
8803
+ });
8804
+ this.variantsModal = page.getByRole("dialog", {
8805
+ name: translate("administration:product:modals.generateVariants")
8806
+ });
8807
+ this.variantsModalHeadline = this.variantsModal.getByRole("heading", {
8808
+ name: translate("administration:product:modals.generateVariants")
8809
+ });
8810
+ this.variantsNextButton = this.variantsModal.getByRole("button", {
8811
+ name: translate("administration:product:buttons.next"),
8812
+ exact: true
8813
+ });
8814
+ this.variantsSaveButton = this.variantsModal.getByRole("button", {
8815
+ name: translate("administration:product:buttons.saveVariants")
8816
+ });
8704
8817
  this.propertyName = (propertyName) => this.variantsModal.getByText(propertyName);
8705
8818
  this.propertyValueCheckbox = (propertyValueName) => this.variantsModal.getByRole("row", { name: propertyValueName }).getByRole("checkbox");
8706
8819
  this.propertyGroupColor = this.variantsModal.getByText(translate("administration:product:detail.colorProperty")).first();
8707
8820
  this.propertyGroupSize = this.variantsModal.getByText(translate("administration:product:detail.sizeProperty")).first();
8708
8821
  this.propertyOptionGrid = this.variantsModal.locator(".sw-property-search__tree-selection__option_grid");
8709
- this.propertyOptionColorBlue = this.propertyOptionGrid.getByRole("row", { name: translate("administration:product:propertyValues.blue") }).getByRole("checkbox");
8710
- this.propertyOptionColorRed = this.propertyOptionGrid.getByRole("row", { name: translate("administration:product:propertyValues.red") }).getByRole("checkbox");
8711
- this.propertyOptionColorGreen = this.propertyOptionGrid.getByRole("row", { name: translate("administration:product:propertyValues.green") }).getByRole("checkbox");
8712
- this.propertyOptionSizeSmall = this.propertyOptionGrid.getByRole("row", { name: translate("administration:product:propertyValues.small") }).getByRole("checkbox");
8713
- this.propertyOptionSizeMedium = this.propertyOptionGrid.getByRole("row", { name: translate("administration:product:propertyValues.medium") }).getByRole("checkbox");
8714
- this.propertyOptionSizeLarge = this.propertyOptionGrid.getByRole("row", { name: translate("administration:product:propertyValues.large") }).getByRole("checkbox");
8822
+ this.propertyOptionColorBlue = this.propertyOptionGrid.getByRole("row", {
8823
+ name: translate("administration:product:propertyValues.blue")
8824
+ }).getByRole("checkbox");
8825
+ this.propertyOptionColorRed = this.propertyOptionGrid.getByRole("row", {
8826
+ name: translate("administration:product:propertyValues.red")
8827
+ }).getByRole("checkbox");
8828
+ this.propertyOptionColorGreen = this.propertyOptionGrid.getByRole("row", {
8829
+ name: translate("administration:product:propertyValues.green")
8830
+ }).getByRole("checkbox");
8831
+ this.propertyOptionSizeSmall = this.propertyOptionGrid.getByRole("row", {
8832
+ name: translate("administration:product:propertyValues.small")
8833
+ }).getByRole("checkbox");
8834
+ this.propertyOptionSizeMedium = this.propertyOptionGrid.getByRole("row", {
8835
+ name: translate("administration:product:propertyValues.medium")
8836
+ }).getByRole("checkbox");
8837
+ this.propertyOptionSizeLarge = this.propertyOptionGrid.getByRole("row", {
8838
+ name: translate("administration:product:propertyValues.large")
8839
+ }).getByRole("checkbox");
8715
8840
  if (satisfies(instanceMeta.version, "<6.7")) {
8716
8841
  this.customFieldCard = page.locator(".sw-card").getByText(translate("administration:customField:general.customFields"));
8717
8842
  } else {
8718
8843
  this.customFieldCard = page.locator(".mt-card").getByText(translate("administration:customField:general.customFields"));
8719
8844
  }
8845
+ this.measurementCard = satisfies(instanceMeta.version, "<6.7.1") ? page.locator(".sw-product-detail-specification__measures-packaging") : page.locator(".sw-product-detail-specification__measurement");
8846
+ this.widthInput = this.measurementCard.getByRole("textbox", { name: translate("administration:product:detail.width"), exact: true });
8847
+ this.heightInput = this.measurementCard.getByRole("textbox", { name: translate("administration:product:detail.height"), exact: true });
8848
+ this.lengthInput = this.measurementCard.getByRole("textbox", { name: translate("administration:product:detail.length"), exact: true });
8849
+ this.weightInput = this.measurementCard.getByRole("textbox", { name: translate("administration:product:detail.weight"), exact: true });
8720
8850
  }
8721
8851
  async getCustomFieldSetCardContentByName(customFieldSetName) {
8722
8852
  let customFieldCard;
8723
8853
  if (satisfies(this.instanceMeta.version, "<6.7")) {
8724
- customFieldCard = this.page.locator(".sw-card").filter({ hasText: translate("administration:customField:general.customFields") });
8854
+ customFieldCard = this.page.locator(".sw-card").filter({
8855
+ hasText: translate("administration:customField:general.customFields")
8856
+ });
8725
8857
  } else {
8726
- customFieldCard = this.page.locator(".mt-card").filter({ hasText: translate("administration:customField:general.customFields") });
8858
+ customFieldCard = this.page.locator(".mt-card").filter({
8859
+ hasText: translate("administration:customField:general.customFields")
8860
+ });
8727
8861
  }
8728
8862
  const customFieldSetTab = customFieldCard.getByText(customFieldSetName);
8729
8863
  const customFieldSetTabCustomContent = customFieldCard.locator(`.sw-custom-field-set-renderer-tab-content__${customFieldSetName}`);
@@ -8740,6 +8874,57 @@ class ProductDetail {
8740
8874
  }
8741
8875
  }
8742
8876
 
8877
+ function fieldName(label) {
8878
+ return new RegExp(`^${label.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*\\*?$`);
8879
+ }
8880
+ class ProductCreate {
8881
+ page;
8882
+ instanceMeta;
8883
+ headline;
8884
+ /**
8885
+ * General information
8886
+ */
8887
+ nameInput;
8888
+ productNumberInput;
8889
+ /**
8890
+ * Prices
8891
+ */
8892
+ priceGrossInput;
8893
+ priceNetInput;
8894
+ /**
8895
+ * Deliverability
8896
+ */
8897
+ stockInput;
8898
+ constructor(page, instanceMeta) {
8899
+ this.page = page;
8900
+ this.instanceMeta = instanceMeta;
8901
+ this.headline = page.locator(".smart-bar__header");
8902
+ this.nameInput = page.getByRole("textbox", {
8903
+ name: fieldName(translate("administration:product:detail.name"))
8904
+ });
8905
+ this.productNumberInput = page.getByRole("textbox", {
8906
+ name: fieldName(translate("administration:product:detail.productNumber"))
8907
+ });
8908
+ this.priceGrossInput = page.locator("#sw-price-field-gross").first();
8909
+ this.priceNetInput = page.locator("#sw-price-field-net").first();
8910
+ this.stockInput = page.getByRole("textbox", {
8911
+ name: translate("administration:product:detail.stock"),
8912
+ exact: true
8913
+ });
8914
+ }
8915
+ /**
8916
+ * Returns the url to the creation page.
8917
+ *
8918
+ * @param creationType - Physical products are created by default, digital products carry a file instead of stock.
8919
+ */
8920
+ url(creationType = "physical") {
8921
+ if (satisfies(this.instanceMeta.version, "<6.7.7")) {
8922
+ return `#/sw/product/create/base?creationStates=${creationType === "digital" ? "is-download" : "is-physical"}`;
8923
+ }
8924
+ return `#/sw/product/create/base?creationType=${creationType}`;
8925
+ }
8926
+ }
8927
+
8743
8928
  class OrderDetail {
8744
8929
  saveButton;
8745
8930
  dataGridContextButton;
@@ -10350,6 +10535,14 @@ class ManufacturerDetail extends ManufacturerCreate {
10350
10535
  }
10351
10536
 
10352
10537
  class ProductListing {
10538
+ /**
10539
+ * Smart bar
10540
+ *
10541
+ * A digital product is only reachable through the split button next to "Add product".
10542
+ */
10543
+ addProductButton;
10544
+ addProductContextMenuButton;
10545
+ addDigitalProductLink;
10353
10546
  /**
10354
10547
  * Multi selection
10355
10548
  */
@@ -10361,12 +10554,33 @@ class ProductListing {
10361
10554
  */
10362
10555
  bulkEditModal;
10363
10556
  startBulkEditButton;
10557
+ /**
10558
+ * Row actions and deletion
10559
+ */
10560
+ deleteContextMenuItem;
10561
+ deleteConfirmationModal;
10562
+ confirmDeleteButton;
10364
10563
  constructor(page) {
10365
10564
  this.page = page;
10565
+ this.addProductButton = page.locator(".smart-bar__actions .sw-product-list__add-physical-button");
10566
+ this.addProductContextMenuButton = page.locator(".sw-product-list__button-context-menu");
10567
+ this.addDigitalProductLink = page.getByRole("link", {
10568
+ name: translate("administration:product:listing.addDigitalProduct")
10569
+ });
10366
10570
  this.productsTable = page.locator(".sw-data-grid__table");
10367
- this.bulkEditButton = page.getByRole("button", { name: translate("administration:product:listing.bulkEdit") });
10571
+ this.bulkEditButton = page.getByRole("button", {
10572
+ name: translate("administration:product:listing.bulkEdit")
10573
+ });
10574
+ this.deleteContextMenuItem = page.locator(".sw-entity-listing__context-menu-edit-delete");
10575
+ this.deleteConfirmationModal = page.locator(".sw-modal");
10576
+ this.confirmDeleteButton = this.deleteConfirmationModal.getByRole("button", {
10577
+ name: translate("administration:product:buttons.delete"),
10578
+ exact: true
10579
+ });
10368
10580
  this.bulkEditModal = page.locator(".sw-product-bulk-edit-modal");
10369
- this.startBulkEditButton = this.bulkEditModal.getByRole("button", { name: translate("administration:product:listing.startBulkEdit") });
10581
+ this.startBulkEditButton = this.bulkEditModal.getByRole("button", {
10582
+ name: translate("administration:product:listing.startBulkEdit")
10583
+ });
10370
10584
  }
10371
10585
  /**
10372
10586
  * Returns the url to the listing page.
@@ -10393,21 +10607,31 @@ class ProductListing {
10393
10607
  * @param productNumber - Product number you are looking for.
10394
10608
  */
10395
10609
  async getProductRow(productNumber) {
10396
- const productTableRow = this.productsTable.locator(".sw-data-grid__row", { hasText: productNumber });
10610
+ const productTableRow = this.productsTable.locator(".sw-data-grid__row", {
10611
+ hasText: productNumber
10612
+ });
10397
10613
  const productNameSelector = ".sw-data-grid__cell--name";
10398
10614
  const productNumberSelector = ".sw-data-grid__cell--productNumber";
10399
10615
  const productManufacturerSelector = ".sw-data-grid__cell--manufacturer-name";
10400
- const productActiveSelector = "sw-icon__regular-checkmark-xs";
10401
- const productInactiveSelector = "sw-icon__regular-times-s";
10616
+ const productDigitalIndicatorSelector = ".sw-product-list__digital-indicator";
10617
+ const productActiveSelector = ".icon--regular-checkmark-xs";
10618
+ const productInactiveSelector = ".icon--regular-times-s";
10619
+ const productStockSelector = ".sw-data-grid__cell--stock";
10620
+ const productAvailableStockSelector = ".sw-data-grid__cell--availableStock";
10621
+ const productActionsMenuSelector = ".sw-data-grid__actions-menu";
10402
10622
  const productPriceSelector = ".sw-data-grid__cell--price-EUR";
10403
10623
  return {
10404
10624
  selectionCheckbox: productTableRow.getByRole("checkbox"),
10405
10625
  productName: productTableRow.locator(productNameSelector),
10626
+ productDigitalIndicator: productTableRow.locator(productDigitalIndicatorSelector),
10406
10627
  productNumber: productTableRow.locator(productNumberSelector),
10407
10628
  productManufacturer: productTableRow.locator(productManufacturerSelector),
10408
- productActive: productTableRow.getByTestId(productActiveSelector),
10409
- productInactive: productTableRow.getByTestId(productInactiveSelector),
10410
- productPrice: productTableRow.locator(productPriceSelector)
10629
+ productActive: productTableRow.locator(productActiveSelector),
10630
+ productInactive: productTableRow.locator(productInactiveSelector),
10631
+ productPrice: productTableRow.locator(productPriceSelector),
10632
+ productStock: productTableRow.locator(productStockSelector),
10633
+ productAvailableStock: productTableRow.locator(productAvailableStockSelector),
10634
+ actionsMenuButton: productTableRow.locator(productActionsMenuSelector)
10411
10635
  };
10412
10636
  }
10413
10637
  }
@@ -11311,6 +11535,7 @@ class DataSharingConsentModal {
11311
11535
 
11312
11536
  const AdminPageObjects = {
11313
11537
  ProductDetail,
11538
+ ProductCreate,
11314
11539
  OrderDetail,
11315
11540
  CustomerListing,
11316
11541
  CustomerDetail,
@@ -11366,6 +11591,9 @@ const test$6 = test$e.extend({
11366
11591
  AdminProductDetail: async ({ AdminPage, InstanceMeta }, use) => {
11367
11592
  await use(new ProductDetail(AdminPage, InstanceMeta));
11368
11593
  },
11594
+ AdminProductCreate: async ({ AdminPage, InstanceMeta }, use) => {
11595
+ await use(new ProductCreate(AdminPage, InstanceMeta));
11596
+ },
11369
11597
  AdminOrderDetail: async ({ AdminPage, InstanceMeta }, use) => {
11370
11598
  await use(new OrderDetail(AdminPage, InstanceMeta));
11371
11599
  },
@@ -12083,6 +12311,88 @@ const SaveProduct = test$e.extend({
12083
12311
  }
12084
12312
  });
12085
12313
 
12314
+ const SaveAndDuplicateProduct = test$e.extend({
12315
+ SaveAndDuplicateProduct: async ({ AdminProductDetail, TestDataService }, use) => {
12316
+ const task = () => {
12317
+ return async function SaveAndDuplicateProduct2() {
12318
+ const page = AdminProductDetail.page;
12319
+ await AdminProductDetail.saveContextMenuButton.click();
12320
+ const cloneRequest = page.waitForResponse((response) => response.url().includes("/api/_action/clone/product/"));
12321
+ await AdminProductDetail.saveAndDuplicateButton.click();
12322
+ const cloneResponse = await cloneRequest;
12323
+ expect(cloneResponse.ok()).toBeTruthy();
12324
+ TestDataService.addCreatedRecord("product", extractIdFromUrl(cloneResponse.url()));
12325
+ const { id: duplicateId } = await cloneResponse.json();
12326
+ TestDataService.addCreatedRecord("product", duplicateId);
12327
+ await page.waitForURL(new RegExp(`#/sw/product/detail/${duplicateId}/`));
12328
+ };
12329
+ };
12330
+ await use(task);
12331
+ }
12332
+ });
12333
+
12334
+ const FillProductBaseData = test$e.extend({
12335
+ FillProductBaseData: async ({ AdminProductCreate, ShopAdmin }, use) => {
12336
+ const task = (product) => {
12337
+ return async function FillProductBaseData2() {
12338
+ await ShopAdmin.fillsIn(AdminProductCreate.nameInput, product.name);
12339
+ if (product.productNumber) {
12340
+ await AdminProductCreate.productNumberInput.fill(product.productNumber);
12341
+ }
12342
+ const priceCalculation = AdminProductCreate.page.waitForResponse((response) => response.url().includes("/api/_action/calculate-price") && response.ok());
12343
+ await ShopAdmin.fillsIn(AdminProductCreate.priceGrossInput, product.grossPrice);
12344
+ await priceCalculation;
12345
+ if (product.stock) {
12346
+ await AdminProductCreate.stockInput.fill(product.stock);
12347
+ }
12348
+ };
12349
+ };
12350
+ await use(task);
12351
+ }
12352
+ });
12353
+
12354
+ const MEDIA_UPLOAD_URL_PATTERN = /\/api\/_action\/media\/(?<mediaId>[0-9a-f]{32})\/(?:finalize-)?upload/;
12355
+ const UploadProductDownloadFile = test$e.extend({
12356
+ UploadProductDownloadFile: async ({ AdminProductDetail, TestDataService }, use) => {
12357
+ const task = (fileName) => {
12358
+ return async function UploadProductDownloadFile2() {
12359
+ const page = AdminProductDetail.page;
12360
+ const fileChooserPromise = page.waitForEvent("filechooser");
12361
+ await AdminProductDetail.uploadDownloadFileButton.click();
12362
+ const fileChooser = await fileChooserPromise;
12363
+ const fileUpload = page.waitForResponse((response) => MEDIA_UPLOAD_URL_PATTERN.test(response.url()) && response.ok());
12364
+ await fileChooser.setFiles({
12365
+ name: `${fileName}.txt`,
12366
+ mimeType: "text/plain",
12367
+ buffer: Buffer.from(`Digital product file of ${fileName}.`)
12368
+ });
12369
+ const uploadResponse = await fileUpload;
12370
+ const mediaId = MEDIA_UPLOAD_URL_PATTERN.exec(uploadResponse.url())?.groups?.["mediaId"];
12371
+ TestDataService.addCreatedRecord("media", mediaId);
12372
+ };
12373
+ };
12374
+ await use(task);
12375
+ }
12376
+ });
12377
+
12378
+ const DeleteProduct = test$e.extend({
12379
+ DeleteProduct: async ({ AdminProductListing }, use) => {
12380
+ const task = (productNumber) => {
12381
+ return async function DeleteProduct2() {
12382
+ const page = AdminProductListing.page;
12383
+ const productRow = await AdminProductListing.getProductRow(productNumber);
12384
+ await productRow["actionsMenuButton"].click();
12385
+ await AdminProductListing.deleteContextMenuItem.click();
12386
+ const deleteRequest = page.waitForResponse((response) => response.request().method() === "DELETE" && response.url().includes("/api/product/"));
12387
+ await AdminProductListing.confirmDeleteButton.click();
12388
+ const deleteResponse = await deleteRequest;
12389
+ expect(deleteResponse.ok()).toBeTruthy();
12390
+ };
12391
+ };
12392
+ await use(task);
12393
+ }
12394
+ });
12395
+
12086
12396
  const ExpectNotification = test$e.extend({
12087
12397
  ExpectNotification: async ({ ShopAdmin, InstanceMeta }, use) => {
12088
12398
  const task = (message, close = true) => {
@@ -12568,6 +12878,10 @@ const SelectExtensionCategory = test$e.extend({
12568
12878
 
12569
12879
  const test$4 = mergeTests(
12570
12880
  SaveProduct,
12881
+ SaveAndDuplicateProduct,
12882
+ FillProductBaseData,
12883
+ UploadProductDownloadFile,
12884
+ DeleteProduct,
12571
12885
  ExpectNotification,
12572
12886
  CreateLinkTypeCategory,
12573
12887
  BulkEditProducts,