Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
run-name: ${{ github.actor }} is running Unit Tests
on:
push:
branches:
- main
- feature/*
pull_request:
branches:
- main

permissions:
contents: write

jobs:
unit-test:
strategy:
matrix:
php_version:
- 8.2
- 8.3
- 8.4
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: mage-os/github-actions/unit-test@main
with:
php_version: ${{ matrix.php_version }}
composer_auth: ${{ secrets.COMPOSER_AUTH }}
33 changes: 33 additions & 0 deletions Test/Unit/Model/Product/RequestTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

/**
* Copyright © 2025 Mage-OS. All rights reserved.
*/

declare(strict_types=1);

namespace MageOS\CatalogDataAI\Test\Unit\Model\Product;

use MageOS\CatalogDataAI\Model\Product\Request;
use PHPUnit\Framework\TestCase;

class RequestTest extends TestCase
{
public function testGetIdReturnsConstructorValue(): void
{
$request = new Request(42, true);
$this->assertSame(42, $request->getId());
}

public function testGetOverwriteReturnsTrue(): void
{
$request = new Request(1, true);
$this->assertTrue($request->getOverwrite());
}

public function testGetOverwriteReturnsFalse(): void
{
$request = new Request(1, false);
$this->assertFalse($request->getOverwrite());
}
}
71 changes: 71 additions & 0 deletions Test/Unit/Trait/ProductMockTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

/**
* Copyright © 2025 Mage-OS. All rights reserved.
*/

declare(strict_types=1);

namespace MageOS\CatalogDataAI\Test\Unit\Trait;

use Magento\Catalog\Model\Product;
use PHPUnit\Framework\MockObject\MockObject;

/**
* Provides product mock creation helpers for unit tests.
*/
trait ProductMockTrait
{
/** @var array<int, array{key: string, value: mixed}> */
private array $productSetDataCalls = [];

/**
* Create a Product mock with configurable data, ID, and store ID.
*
* @param array<string, mixed> $attributes Data returned by getData()
* @param int|null $id Product ID (falls back to $attributes['entity_id'])
* @param int|null $storeId Store ID (falls back to $attributes['store_id'], then 0)
* @param bool $trackSetData When true, setData() calls are recorded in $productSetDataCalls
* @return Product&MockObject
*/
protected function createProductMock(
array $attributes = [],
?int $id = null,
?int $storeId = null,
bool $trackSetData = false
): Product&MockObject {
$product = $this->getMockBuilder(Product::class)
->disableOriginalConstructor()
->getMock();

$product->method('getData')
->willReturnCallback(function (?string $key = null) use ($attributes) {
if ($key === null) {
return $attributes;
}
return $attributes[$key] ?? null;
});

$product->method('getId')->willReturn($id ?? ($attributes['entity_id'] ?? null));
$product->method('getStoreId')->willReturn($storeId ?? ($attributes['store_id'] ?? 0));

if ($trackSetData) {
$this->productSetDataCalls = [];
$product->method('setData')
->willReturnCallback(function (string $key, $value) use ($product) {
$this->productSetDataCalls[] = ['key' => $key, 'value' => $value];
return $product;
});
}

return $product;
}

/**
* @return array<int, array{key: string, value: mixed}>
*/
protected function getProductSetDataCalls(): array
{
return $this->productSetDataCalls;
}
}
24 changes: 24 additions & 0 deletions Test/Unit/bootstrap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

/**
* Bootstrap for standalone unit tests (CI).
*
* Uses Magento's official test framework autoloader to generate Factory
* and Proxy classes on demand, since code generation (setup:di:compile)
* is not available outside a full Magento installation.
*/

use Magento\Framework\Code\Generator\Io;
use Magento\Framework\Filesystem\Driver\File;
use Magento\Framework\TestFramework\Unit\Autoloader\FactoryGenerator;
use Magento\Framework\TestFramework\Unit\Autoloader\GeneratedClassesAutoloader;
use Magento\Framework\TestFramework\Unit\Autoloader\ProxyGenerator;

require_once dirname(__DIR__, 2) . '/vendor/autoload.php';

$generatorIo = new Io(new File(), sys_get_temp_dir() . '/mageos-catalogdataai-generated');
$autoloader = new GeneratedClassesAutoloader(
[new FactoryGenerator(), new ProxyGenerator()],
$generatorIo
);
spl_autoload_register([$autoloader, 'load']);
13 changes: 12 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,15 @@
],
"require": {
"php": "^8.1",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
"magento/module-store": "*",
"magento/module-ui": "*",
"openai-php/client": "*"
},
"require-dev": {
"phpunit/phpunit": "^9.5"
"phpunit/phpunit": "^9.5||^10.0"
},
"autoload": {
"files": [
Expand All @@ -32,5 +37,11 @@
"psr-4": {
"MageOS\\CatalogDataAI\\": ""
}
},
"scripts": {
"test": "phpunit"
},
"config": {
"allow-plugins": false
}
}
16 changes: 16 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true"
verbose="true"
stopOnFailure="false"
bootstrap="Test/Unit/bootstrap.php">
<testsuites>
<testsuite name="Unit Tests">
<directory>Test/Unit</directory>
</testsuite>
</testsuites>
<php>
<ini name="error_reporting" value="E_ALL"/>
<ini name="display_errors" value="1"/>
<ini name="display_startup_errors" value="1"/>
</php>
</phpunit>
Loading