Backeup configs & cleanup of files and db
This commit is contained in:
@@ -1,2 +0,0 @@
|
||||
# Linking tests
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
"""
|
||||
Tests for CandidateEngine
|
||||
"""
|
||||
from django.test import TestCase
|
||||
from igny8_core.business.content.models import Content
|
||||
from igny8_core.business.linking.services.candidate_engine import CandidateEngine
|
||||
from igny8_core.api.tests.test_integration_base import IntegrationTestBase
|
||||
|
||||
|
||||
class CandidateEngineTests(IntegrationTestBase):
|
||||
"""Tests for CandidateEngine"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.engine = CandidateEngine()
|
||||
|
||||
# Create source content
|
||||
self.source_content = Content.objects.create(
|
||||
account=self.account,
|
||||
site=self.site,
|
||||
sector=self.sector,
|
||||
title="Source Content",
|
||||
html_content="<p>Source content about test keyword.</p>",
|
||||
primary_keyword="test keyword",
|
||||
secondary_keywords=["keyword1", "keyword2"],
|
||||
categories=["category1"],
|
||||
tags=["tag1", "tag2"],
|
||||
word_count=100,
|
||||
status='draft'
|
||||
)
|
||||
|
||||
# Create relevant content (same keyword)
|
||||
self.relevant_content = Content.objects.create(
|
||||
account=self.account,
|
||||
site=self.site,
|
||||
sector=self.sector,
|
||||
title="Relevant Content",
|
||||
html_content="<p>Relevant content about test keyword.</p>",
|
||||
primary_keyword="test keyword",
|
||||
secondary_keywords=["keyword1"],
|
||||
categories=["category1"],
|
||||
tags=["tag1"],
|
||||
word_count=150,
|
||||
status='draft'
|
||||
)
|
||||
|
||||
# Create less relevant content (different keyword)
|
||||
self.less_relevant = Content.objects.create(
|
||||
account=self.account,
|
||||
site=self.site,
|
||||
sector=self.sector,
|
||||
title="Less Relevant",
|
||||
html_content="<p>Different content.</p>",
|
||||
primary_keyword="different keyword",
|
||||
word_count=100,
|
||||
status='draft'
|
||||
)
|
||||
|
||||
def test_find_candidates_returns_relevant_content(self):
|
||||
"""Test that find_candidates returns relevant content"""
|
||||
candidates = self.engine.find_candidates(self.source_content, max_candidates=10)
|
||||
|
||||
# Should find relevant content
|
||||
candidate_ids = [c['content_id'] for c in candidates]
|
||||
self.assertIn(self.relevant_content.id, candidate_ids)
|
||||
|
||||
def test_find_candidates_scores_by_relevance(self):
|
||||
"""Test that candidates are scored by relevance"""
|
||||
candidates = self.engine.find_candidates(self.source_content, max_candidates=10)
|
||||
|
||||
# Relevant content should have higher score
|
||||
relevant_candidate = next((c for c in candidates if c['content_id'] == self.relevant_content.id), None)
|
||||
self.assertIsNotNone(relevant_candidate)
|
||||
self.assertGreater(relevant_candidate['relevance_score'], 0)
|
||||
|
||||
def test_find_candidates_excludes_self(self):
|
||||
"""Test that source content is excluded from candidates"""
|
||||
candidates = self.engine.find_candidates(self.source_content, max_candidates=10)
|
||||
|
||||
candidate_ids = [c['content_id'] for c in candidates]
|
||||
self.assertNotIn(self.source_content.id, candidate_ids)
|
||||
|
||||
def test_find_candidates_respects_account_isolation(self):
|
||||
"""Test that candidates are only from same account"""
|
||||
# Create content from different account
|
||||
from igny8_core.auth.models import Account
|
||||
other_account = Account.objects.create(
|
||||
name="Other Account",
|
||||
slug="other-account",
|
||||
plan=self.plan,
|
||||
owner=self.user
|
||||
)
|
||||
|
||||
other_content = Content.objects.create(
|
||||
account=other_account,
|
||||
site=self.site,
|
||||
sector=self.sector,
|
||||
title="Other Account Content",
|
||||
primary_keyword="test keyword",
|
||||
word_count=100,
|
||||
status='draft'
|
||||
)
|
||||
|
||||
candidates = self.engine.find_candidates(self.source_content, max_candidates=10)
|
||||
candidate_ids = [c['content_id'] for c in candidates]
|
||||
self.assertNotIn(other_content.id, candidate_ids)
|
||||
|
||||
def test_find_candidates_returns_empty_for_no_content(self):
|
||||
"""Test that empty list is returned when no content"""
|
||||
empty_content = Content.objects.create(
|
||||
account=self.account,
|
||||
site=self.site,
|
||||
sector=self.sector,
|
||||
title="Empty",
|
||||
html_content="",
|
||||
word_count=0,
|
||||
status='draft'
|
||||
)
|
||||
|
||||
candidates = self.engine.find_candidates(empty_content, max_candidates=10)
|
||||
self.assertEqual(len(candidates), 0)
|
||||
|
||||
def test_find_candidates_respects_max_candidates(self):
|
||||
"""Test that max_candidates limit is respected"""
|
||||
# Create multiple relevant content items
|
||||
for i in range(15):
|
||||
Content.objects.create(
|
||||
account=self.account,
|
||||
site=self.site,
|
||||
sector=self.sector,
|
||||
title=f"Content {i}",
|
||||
primary_keyword="test keyword",
|
||||
word_count=100,
|
||||
status='draft'
|
||||
)
|
||||
|
||||
candidates = self.engine.find_candidates(self.source_content, max_candidates=5)
|
||||
self.assertLessEqual(len(candidates), 5)
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
"""
|
||||
Tests for InjectionEngine
|
||||
"""
|
||||
from django.test import TestCase
|
||||
from igny8_core.business.content.models import Content
|
||||
from igny8_core.business.linking.services.injection_engine import InjectionEngine
|
||||
from igny8_core.api.tests.test_integration_base import IntegrationTestBase
|
||||
|
||||
|
||||
class InjectionEngineTests(IntegrationTestBase):
|
||||
"""Tests for InjectionEngine"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.engine = InjectionEngine()
|
||||
|
||||
# Create content with HTML
|
||||
self.content = Content.objects.create(
|
||||
account=self.account,
|
||||
site=self.site,
|
||||
sector=self.sector,
|
||||
title="Test Content",
|
||||
html_content="<p>This is test content with some keywords and text.</p>",
|
||||
word_count=100,
|
||||
status='draft'
|
||||
)
|
||||
|
||||
def test_inject_links_adds_links_to_html(self):
|
||||
"""Test that links are injected into HTML content"""
|
||||
candidates = [{
|
||||
'content_id': 1,
|
||||
'title': 'Target Content',
|
||||
'url': '/content/1/',
|
||||
'relevance_score': 50,
|
||||
'anchor_text': 'keywords'
|
||||
}]
|
||||
|
||||
result = self.engine.inject_links(self.content, candidates, max_links=5)
|
||||
|
||||
# Check that link was added
|
||||
self.assertIn('<a href="/content/1/" class="internal-link">keywords</a>', result['html_content'])
|
||||
self.assertEqual(result['links_added'], 1)
|
||||
self.assertEqual(len(result['links']), 1)
|
||||
|
||||
def test_inject_links_respects_max_links(self):
|
||||
"""Test that max_links limit is respected"""
|
||||
candidates = [
|
||||
{'content_id': i, 'title': f'Content {i}', 'url': f'/content/{i}/',
|
||||
'relevance_score': 50, 'anchor_text': f'keyword{i}'}
|
||||
for i in range(10)
|
||||
]
|
||||
|
||||
# Update HTML to include all anchor texts
|
||||
self.content.html_content = "<p>" + " ".join([f'keyword{i}' for i in range(10)]) + "</p>"
|
||||
self.content.save()
|
||||
|
||||
result = self.engine.inject_links(self.content, candidates, max_links=3)
|
||||
|
||||
self.assertLessEqual(result['links_added'], 3)
|
||||
self.assertLessEqual(len(result['links']), 3)
|
||||
|
||||
def test_inject_links_returns_unchanged_when_no_candidates(self):
|
||||
"""Test that content is unchanged when no candidates"""
|
||||
original_html = self.content.html_content
|
||||
|
||||
result = self.engine.inject_links(self.content, [], max_links=5)
|
||||
|
||||
self.assertEqual(result['html_content'], original_html)
|
||||
self.assertEqual(result['links_added'], 0)
|
||||
self.assertEqual(len(result['links']), 0)
|
||||
|
||||
def test_inject_links_returns_unchanged_when_no_html(self):
|
||||
"""Test that empty HTML returns unchanged"""
|
||||
self.content.html_content = ""
|
||||
self.content.save()
|
||||
|
||||
candidates = [{
|
||||
'content_id': 1,
|
||||
'title': 'Target',
|
||||
'url': '/content/1/',
|
||||
'relevance_score': 50,
|
||||
'anchor_text': 'test'
|
||||
}]
|
||||
|
||||
result = self.engine.inject_links(self.content, candidates, max_links=5)
|
||||
|
||||
self.assertEqual(result['html_content'], "")
|
||||
self.assertEqual(result['links_added'], 0)
|
||||
|
||||
def test_inject_links_case_insensitive_matching(self):
|
||||
"""Test that anchor text matching is case-insensitive"""
|
||||
self.content.html_content = "<p>This is TEST content.</p>"
|
||||
self.content.save()
|
||||
|
||||
candidates = [{
|
||||
'content_id': 1,
|
||||
'title': 'Target',
|
||||
'url': '/content/1/',
|
||||
'relevance_score': 50,
|
||||
'anchor_text': 'test'
|
||||
}]
|
||||
|
||||
result = self.engine.inject_links(self.content, candidates, max_links=5)
|
||||
|
||||
# Should find and replace despite case difference
|
||||
self.assertIn('internal-link', result['html_content'])
|
||||
self.assertEqual(result['links_added'], 1)
|
||||
|
||||
def test_inject_links_prevents_duplicate_links(self):
|
||||
"""Test that same candidate is not linked twice"""
|
||||
candidates = [
|
||||
{
|
||||
'content_id': 1,
|
||||
'title': 'Target',
|
||||
'url': '/content/1/',
|
||||
'relevance_score': 50,
|
||||
'anchor_text': 'test'
|
||||
},
|
||||
{
|
||||
'content_id': 1, # Same content_id
|
||||
'title': 'Target',
|
||||
'url': '/content/1/',
|
||||
'relevance_score': 40,
|
||||
'anchor_text': 'test'
|
||||
}
|
||||
]
|
||||
|
||||
self.content.html_content = "<p>This is test content with test keywords.</p>"
|
||||
self.content.save()
|
||||
|
||||
result = self.engine.inject_links(self.content, candidates, max_links=5)
|
||||
|
||||
# Should only add one link despite two candidates
|
||||
self.assertEqual(result['links_added'], 1)
|
||||
self.assertEqual(result['html_content'].count('internal-link'), 1)
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
"""
|
||||
Tests for LinkerService
|
||||
"""
|
||||
from unittest.mock import Mock, patch, MagicMock
|
||||
from django.test import TestCase
|
||||
from igny8_core.business.content.models import Content
|
||||
from igny8_core.business.linking.services.linker_service import LinkerService
|
||||
from igny8_core.business.billing.exceptions import InsufficientCreditsError
|
||||
from igny8_core.api.tests.test_integration_base import IntegrationTestBase
|
||||
|
||||
|
||||
class LinkerServiceTests(IntegrationTestBase):
|
||||
"""Tests for LinkerService"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.service = LinkerService()
|
||||
|
||||
# Create test content
|
||||
self.content = Content.objects.create(
|
||||
account=self.account,
|
||||
site=self.site,
|
||||
sector=self.sector,
|
||||
title="Test Content",
|
||||
html_content="<p>This is test content with some keywords.</p>",
|
||||
primary_keyword="test keyword",
|
||||
word_count=100,
|
||||
status='draft'
|
||||
)
|
||||
|
||||
# Create another content for linking
|
||||
self.target_content = Content.objects.create(
|
||||
account=self.account,
|
||||
site=self.site,
|
||||
sector=self.sector,
|
||||
title="Target Content",
|
||||
html_content="<p>Target content for linking.</p>",
|
||||
primary_keyword="test keyword",
|
||||
word_count=150,
|
||||
status='draft'
|
||||
)
|
||||
|
||||
@patch('igny8_core.business.linking.services.linker_service.CreditService.check_credits')
|
||||
@patch('igny8_core.business.linking.services.linker_service.CandidateEngine.find_candidates')
|
||||
@patch('igny8_core.business.linking.services.linker_service.InjectionEngine.inject_links')
|
||||
@patch('igny8_core.business.linking.services.linker_service.CreditService.deduct_credits_for_operation')
|
||||
def test_process_single_content(self, mock_deduct, mock_inject, mock_find, mock_check):
|
||||
"""Test processing single content for linking"""
|
||||
# Setup mocks
|
||||
mock_check.return_value = True
|
||||
mock_find.return_value = [{
|
||||
'content_id': self.target_content.id,
|
||||
'title': 'Target Content',
|
||||
'url': '/content/2/',
|
||||
'relevance_score': 50,
|
||||
'anchor_text': 'test keyword'
|
||||
}]
|
||||
mock_inject.return_value = {
|
||||
'html_content': '<p>This is test content with <a href="/content/2/">test keyword</a>.</p>',
|
||||
'links': [{
|
||||
'content_id': self.target_content.id,
|
||||
'anchor_text': 'test keyword',
|
||||
'url': '/content/2/'
|
||||
}],
|
||||
'links_added': 1
|
||||
}
|
||||
|
||||
# Execute
|
||||
result = self.service.process(self.content.id)
|
||||
|
||||
# Assertions
|
||||
self.assertEqual(result.id, self.content.id)
|
||||
self.assertEqual(result.linker_version, 1)
|
||||
self.assertEqual(len(result.internal_links), 1)
|
||||
mock_check.assert_called_once_with(self.account, 'linking')
|
||||
mock_deduct.assert_called_once()
|
||||
|
||||
@patch('igny8_core.business.linking.services.linker_service.CreditService.check_credits')
|
||||
def test_process_insufficient_credits(self, mock_check):
|
||||
"""Test that InsufficientCreditsError is raised when credits are insufficient"""
|
||||
mock_check.side_effect = InsufficientCreditsError("Insufficient credits")
|
||||
|
||||
with self.assertRaises(InsufficientCreditsError):
|
||||
self.service.process(self.content.id)
|
||||
|
||||
def test_process_content_not_found(self):
|
||||
"""Test that ValueError is raised when content doesn't exist"""
|
||||
with self.assertRaises(ValueError):
|
||||
self.service.process(99999)
|
||||
|
||||
@patch('igny8_core.business.linking.services.linker_service.LinkerService.process')
|
||||
def test_batch_process_multiple_content(self, mock_process):
|
||||
"""Test batch processing multiple content items"""
|
||||
# Create additional content
|
||||
content2 = Content.objects.create(
|
||||
account=self.account,
|
||||
site=self.site,
|
||||
sector=self.sector,
|
||||
title="Content 2",
|
||||
html_content="<p>Content 2</p>",
|
||||
word_count=100,
|
||||
status='draft'
|
||||
)
|
||||
|
||||
# Setup mock
|
||||
mock_process.side_effect = [self.content, content2]
|
||||
|
||||
# Execute
|
||||
results = self.service.batch_process([self.content.id, content2.id])
|
||||
|
||||
# Assertions
|
||||
self.assertEqual(len(results), 2)
|
||||
self.assertEqual(mock_process.call_count, 2)
|
||||
|
||||
@patch('igny8_core.business.linking.services.linker_service.LinkerService.process')
|
||||
def test_batch_process_handles_partial_failure(self, mock_process):
|
||||
"""Test batch processing handles partial failures"""
|
||||
# Setup mock to fail on second item
|
||||
mock_process.side_effect = [self.content, Exception("Processing failed")]
|
||||
|
||||
# Execute
|
||||
results = self.service.batch_process([self.content.id, 99999])
|
||||
|
||||
# Assertions - should continue processing other items
|
||||
self.assertEqual(len(results), 1)
|
||||
self.assertEqual(results[0].id, self.content.id)
|
||||
|
||||
@patch('igny8_core.business.linking.services.linker_service.CreditService.check_credits')
|
||||
@patch('igny8_core.business.linking.services.linker_service.CandidateEngine.find_candidates')
|
||||
def test_process_no_candidates_found(self, mock_find, mock_check):
|
||||
"""Test processing when no candidates are found"""
|
||||
mock_check.return_value = True
|
||||
mock_find.return_value = []
|
||||
|
||||
# Execute
|
||||
result = self.service.process(self.content.id)
|
||||
|
||||
# Assertions - should return content unchanged
|
||||
self.assertEqual(result.id, self.content.id)
|
||||
self.assertEqual(result.linker_version, 0) # Not incremented
|
||||
|
||||
@@ -1,193 +0,0 @@
|
||||
"""
|
||||
Tests for Universal Content Types Linking (Phase 8)
|
||||
Tests for product and taxonomy linking
|
||||
"""
|
||||
from unittest.mock import patch, MagicMock
|
||||
from django.test import TestCase
|
||||
from igny8_core.business.content.models import Content
|
||||
from igny8_core.business.linking.services.linker_service import LinkerService
|
||||
from igny8_core.api.tests.test_integration_base import IntegrationTestBase
|
||||
|
||||
|
||||
class UniversalContentLinkingTests(IntegrationTestBase):
|
||||
"""Tests for Phase 8: Universal Content Types Linking"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
# Add credits to account for testing
|
||||
self.account.credits = 10000
|
||||
self.account.save()
|
||||
self.linker_service = LinkerService()
|
||||
|
||||
# Create product content
|
||||
self.product_content = Content.objects.create(
|
||||
account=self.account,
|
||||
site=self.site,
|
||||
sector=self.sector,
|
||||
title='Test Product',
|
||||
html_content='<p>Product content with features and specifications.</p>',
|
||||
entity_type='product',
|
||||
json_blocks=[
|
||||
{'type': 'features', 'heading': 'Features', 'items': ['Feature 1', 'Feature 2']}
|
||||
],
|
||||
structure_data={'product_type': 'software'},
|
||||
word_count=1500,
|
||||
status='draft'
|
||||
)
|
||||
|
||||
# Create related product
|
||||
self.related_product = Content.objects.create(
|
||||
account=self.account,
|
||||
site=self.site,
|
||||
sector=self.sector,
|
||||
title='Related Product',
|
||||
html_content='<p>Related product content.</p>',
|
||||
entity_type='product',
|
||||
structure_data={'product_type': 'software'},
|
||||
word_count=1500,
|
||||
status='draft'
|
||||
)
|
||||
|
||||
# Create service content
|
||||
self.service_content = Content.objects.create(
|
||||
account=self.account,
|
||||
site=self.site,
|
||||
sector=self.sector,
|
||||
title='Related Service',
|
||||
html_content='<p>Service content.</p>',
|
||||
entity_type='service',
|
||||
word_count=1800,
|
||||
status='draft'
|
||||
)
|
||||
|
||||
# Create taxonomy content
|
||||
self.taxonomy_content = Content.objects.create(
|
||||
account=self.account,
|
||||
site=self.site,
|
||||
sector=self.sector,
|
||||
title='Test Taxonomy',
|
||||
html_content='<p>Taxonomy content with categories.</p>',
|
||||
entity_type='taxonomy',
|
||||
json_blocks=[
|
||||
{
|
||||
'type': 'categories',
|
||||
'heading': 'Categories',
|
||||
'items': [
|
||||
{'name': 'Category 1', 'description': 'Desc 1', 'subcategories': []}
|
||||
]
|
||||
}
|
||||
],
|
||||
word_count=1200,
|
||||
status='draft'
|
||||
)
|
||||
|
||||
# Create related taxonomy
|
||||
self.related_taxonomy = Content.objects.create(
|
||||
account=self.account,
|
||||
site=self.site,
|
||||
sector=self.sector,
|
||||
title='Related Taxonomy',
|
||||
html_content='<p>Related taxonomy content.</p>',
|
||||
entity_type='taxonomy',
|
||||
word_count=1200,
|
||||
status='draft'
|
||||
)
|
||||
|
||||
@patch('igny8_core.business.linking.services.linker_service.InjectionEngine.inject_links')
|
||||
@patch('igny8_core.business.linking.services.linker_service.CreditService.check_credits')
|
||||
@patch('igny8_core.business.linking.services.linker_service.CreditService.deduct_credits_for_operation')
|
||||
def test_linking_works_for_products(self, mock_deduct, mock_check_credits, mock_inject_links):
|
||||
"""
|
||||
Test: Linking works for all content types (products, taxonomies)
|
||||
Task 20: Verify product linking finds related products and services
|
||||
"""
|
||||
# Mock injection engine
|
||||
mock_inject_links.return_value = {
|
||||
'html_content': '<p>Product content with links.</p>',
|
||||
'links': [
|
||||
{'content_id': self.related_product.id, 'anchor_text': 'Related Product'},
|
||||
{'content_id': self.service_content.id, 'anchor_text': 'Related Service'}
|
||||
],
|
||||
'links_added': 2
|
||||
}
|
||||
|
||||
# Process product linking
|
||||
result = self.linker_service.process_product(self.product_content.id)
|
||||
|
||||
# Verify result
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(result.entity_type, 'product')
|
||||
self.assertIsNotNone(result.internal_links)
|
||||
self.assertEqual(len(result.internal_links), 2)
|
||||
self.assertEqual(result.linker_version, 1)
|
||||
|
||||
# Verify injection was called
|
||||
mock_inject_links.assert_called_once()
|
||||
candidates = mock_inject_links.call_args[0][1]
|
||||
self.assertGreater(len(candidates), 0)
|
||||
|
||||
# Verify product candidates were found
|
||||
product_candidates = [c for c in candidates if c.get('content_id') == self.related_product.id]
|
||||
self.assertGreater(len(product_candidates), 0)
|
||||
|
||||
@patch('igny8_core.business.linking.services.linker_service.InjectionEngine.inject_links')
|
||||
@patch('igny8_core.business.linking.services.linker_service.CreditService.check_credits')
|
||||
@patch('igny8_core.business.linking.services.linker_service.CreditService.deduct_credits_for_operation')
|
||||
def test_linking_works_for_taxonomies(self, mock_deduct, mock_check_credits, mock_inject_links):
|
||||
"""
|
||||
Test: Linking works for all content types (products, taxonomies)
|
||||
Task 20: Verify taxonomy linking finds related taxonomies and content
|
||||
"""
|
||||
# Mock injection engine
|
||||
mock_inject_links.return_value = {
|
||||
'html_content': '<p>Taxonomy content with links.</p>',
|
||||
'links': [
|
||||
{'content_id': self.related_taxonomy.id, 'anchor_text': 'Related Taxonomy'}
|
||||
],
|
||||
'links_added': 1
|
||||
}
|
||||
|
||||
# Process taxonomy linking
|
||||
result = self.linker_service.process_taxonomy(self.taxonomy_content.id)
|
||||
|
||||
# Verify result
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(result.entity_type, 'taxonomy')
|
||||
self.assertIsNotNone(result.internal_links)
|
||||
self.assertEqual(len(result.internal_links), 1)
|
||||
self.assertEqual(result.linker_version, 1)
|
||||
|
||||
# Verify injection was called
|
||||
mock_inject_links.assert_called_once()
|
||||
candidates = mock_inject_links.call_args[0][1]
|
||||
self.assertGreater(len(candidates), 0)
|
||||
|
||||
# Verify taxonomy candidates were found
|
||||
taxonomy_candidates = [c for c in candidates if c.get('content_id') == self.related_taxonomy.id]
|
||||
self.assertGreater(len(taxonomy_candidates), 0)
|
||||
|
||||
def test_product_linking_finds_related_products(self):
|
||||
"""
|
||||
Test: Linking works for all content types (products, taxonomies)
|
||||
Task 20: Verify _find_product_candidates finds related products
|
||||
"""
|
||||
candidates = self.linker_service._find_product_candidates(self.product_content)
|
||||
|
||||
# Should find related product
|
||||
product_ids = [c['content_id'] for c in candidates]
|
||||
self.assertIn(self.related_product.id, product_ids)
|
||||
|
||||
# Should find related service
|
||||
self.assertIn(self.service_content.id, product_ids)
|
||||
|
||||
def test_taxonomy_linking_finds_related_taxonomies(self):
|
||||
"""
|
||||
Test: Linking works for all content types (products, taxonomies)
|
||||
Task 20: Verify _find_taxonomy_candidates finds related taxonomies
|
||||
"""
|
||||
candidates = self.linker_service._find_taxonomy_candidates(self.taxonomy_content)
|
||||
|
||||
# Should find related taxonomy
|
||||
taxonomy_ids = [c['content_id'] for c in candidates]
|
||||
self.assertIn(self.related_taxonomy.id, taxonomy_ids)
|
||||
|
||||
Reference in New Issue
Block a user