{"id":183,"date":"2023-08-24T12:18:00","date_gmt":"2023-08-24T12:18:00","guid":{"rendered":"https:\/\/yulianavarzar.com\/?p=183"},"modified":"2023-08-24T12:18:00","modified_gmt":"2023-08-24T12:18:00","slug":"a-layered-testing-strategy-for-sme-loan-platform","status":"publish","type":"post","link":"https:\/\/yulianavarzar.com\/?p=183","title":{"rendered":"A Layered Testing Strategy for SME Loan Platform"},"content":{"rendered":"\n<p>While this Loan App system dates back to 2018\u2014built on Laravel 5.x and a React 16 (without Hooks) front-end, it had a structured, layered test suite. In 2018, the popular choices included ESLint and JSCS for linting, PHPUnit for PHP, Jest\u00a0+ Enzyme for React, and Cypress or Selenium for end-to-end. Below, we\u2019ll map out five layers of testing with tools available at the time.<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>Static Analysis<\/strong> (ESLint, JSCS, PHP_CodeSniffer, PHPMD)<\/li>\n\n\n\n<li><strong>Unit Tests<\/strong> (PHPUnit, Jest + Enzyme)<\/li>\n\n\n\n<li><strong>Integration Tests<\/strong> (Laravel HTTP Tests, nock or fetch-mock)<\/li>\n\n\n\n<li><strong>Component Tests<\/strong> (Jest\u00a0+ Enzyme, React Test Utilities)<\/li>\n\n\n\n<li><strong>End-to-End Tests<\/strong> (Cypress or Selenium WebDriver)<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">1. Static Analysis: Linting &amp; Style Checking<\/h2>\n\n\n\n<p><strong>Tools:<\/strong> ESLint (with ES6\/React plugins), JSCS, Prettier (early adoption), PHP_CodeSniffer, PHPMD<\/p>\n\n\n\n<p><strong>Why?<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Enforce consistent style and catch syntax errors before runtime<\/li>\n\n\n\n<li>Identify code smells in PHP (unused vars, complexity) via PHPMD<\/li>\n\n\n\n<li>Automate formatting with Prettier or JSCS<\/li>\n<\/ul>\n\n\n\n<p><strong>Front\u2011end Example (<\/strong><code><strong>.eslintrc.js<\/strong><\/code><strong>):<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code has-background-color has-secondary-background-color has-text-color has-background has-link-color wp-elements-898def73808418264eb8039c613c3060\"><code>module.exports = {\n  parser: 'babel-eslint',  \/\/ support ES6+ syntax\n  extends: &#91;'eslint:recommended', 'plugin:react\/recommended'],\n  plugins: &#91;'react'],\n  env: { browser: true, jest: true, es6: true },\n  rules: { 'react\/prop-types': 'warn', 'no-console': 'off' },\n};<\/code><\/pre>\n\n\n\n<p><strong>Back\u2011end Example (<\/strong><code><strong>.phpcs.xml<\/strong><\/code><strong>):<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code has-background-color has-secondary-background-color has-text-color has-background has-link-color wp-elements-40d3c5e1671ccb08463b031e5cc3f275\"><code>&lt;ruleset name=\"LoanApp\">\n  &lt;rule ref=\"PSR2\"\/>\n  &lt;rule ref=\"PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Namespaces\\NamespaceDeclarationSniff\"\/>\n&lt;\/ruleset><\/code><\/pre>\n\n\n\n<p>Run these tools locally and integrate into CI to block bad commits.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. Unit Tests: Isolate Core Logic<\/h2>\n\n\n\n<p><strong>Tools:<\/strong> PHPUnit 6.x (Laravel built\u2011in), Jest 22.x, Enzyme 3.x<\/p>\n\n\n\n<p><strong>PHPUnit Example (InterestCalculator):<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code has-background-color has-secondary-background-color has-text-color has-background has-link-color wp-elements-3027b1921678d624f5eb32e5ce55c775\"><code>\/\/ app\/Services\/InterestCalculator.php\npublic function calculate($principal, $rate, $days) {\n    return round($principal * $rate\/365 * $days, 2);\n}\n\/\/ tests\/Unit\/InterestCalculatorTest.php\nclass InterestCalculatorTest extends TestCase {\n    public function testDailyInterest(): void {\n        $calc = new \\App\\Services\\InterestCalculator();\n        $this->assertEquals(8.22, $calc->calculate(10000, 0.30, 10));\n    }\n}<\/code><\/pre>\n\n\n\n<p><strong>Jest\u00a0+ Enzyme Example (DocumentTypeUtil):<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code has-background-color has-secondary-background-color has-text-color has-background has-link-color wp-elements-87ae017f3eb4fe4fdb50712349b59526\"><code>\/\/ src\/utils\/documentType.js\nexport function isValidPdf(file) {\n  return file.type === 'application\/pdf';\n}\n\n\/\/ __tests__\/documentType.test.js\nimport { isValidPdf } from '..\/src\/utils\/documentType';\n\ntest('accepts PDF files', () => {\n  const file = { type: 'application\/pdf' };\n  expect(isValidPdf(file)).toBe(true);\n});\n\ntest('rejects non\u2011PDF files', () => {\n  const file = { type: 'image\/png' };\n  expect(isValidPdf(file)).toBe(false);\n});<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">3. Integration Tests: API &amp; Data Layer<\/h2>\n\n\n\n<p><strong>Tools:<\/strong> Laravel HTTP Tests (built\u2011in), nock (for Node), fetch\u2011mock or jest\u2011fetch\u2011mock<\/p>\n\n\n\n<p><strong>Laravel Example (<\/strong><code><strong>LoanRequestController<\/strong><\/code><strong>):<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code has-background-color has-secondary-background-color has-text-color has-background has-link-color wp-elements-12a827f395d10f4f359585a28b2bdbef\"><code>\/\/ tests\/Feature\/LoanRequestTest.php\npublic function testCreateLoanRequest(): void {\n    $user = factory(User::class)->create();\n    $this->actingAs($user)\n         ->postJson('\/api\/loans', &#91;\n           'institution_id' => 1,\n           'net_worth' => 50000,\n           'collaterals' => &#91;'Real Estate'],\n         ])\n         ->assertStatus(201)\n         ->assertJson(&#91;'status' => 'pending']);\n    $this->assertDatabaseHas('loan_requests', &#91;'user_id' => $user->id]);\n}<\/code><\/pre>\n\n\n\n<p><strong>React Integration (fetch-mock):<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code has-background-color has-secondary-background-color has-text-color has-background has-link-color wp-elements-62d52894497c4fb72bf975d3afbbfc54\"><code>\/\/ __tests__\/upload.integration.js\nimport fetchMock from 'fetch-mock';\nimport { uploadDocument } from '..\/src\/api';\n\ndescribe('uploadDocument', () => {\n  afterEach(() => fetchMock.restore());\n\n  it('returns URL on success', async () => {\n    fetchMock.post('\/api\/uploads', { url: '\/docs\/1.pdf' });\n    const response = await uploadDocument(new Blob());\n    expect(response.url).toBe('\/docs\/1.pdf');\n  });\n});<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">4. Component Tests: React UI Assertions<\/h2>\n\n\n\n<p><strong>Tools:<\/strong> Jest\u00a0+ Enzyme (shallow, mount)<\/p>\n\n\n\n<p><strong>Example (LoanStatusCard):<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code has-background-color has-secondary-background-color has-text-color has-background has-link-color wp-elements-c7fb37f7e56a7e29b8297573f298508e\"><code>import React from 'react';\nimport { shallow } from 'enzyme';\nimport LoanStatusCard from '..\/src\/components\/LoanStatusCard';\n\ndescribe('&lt;LoanStatusCard \/>', () => {\n  it('shows pending status', () => {\n    const wrapper = shallow(&lt;LoanStatusCard status=\"pending\"\/>);\n    expect(wrapper.text()).toContain('pending');\n  });\n});<\/code><\/pre>\n\n\n\n<p>Mock contexts or Redux stores as needed to supply props and state.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5. End\u2011to\u2011End Tests: Full User Journeys<\/h2>\n\n\n\n<p><strong>Tools:<\/strong> Cypress 3.x (released mid\u20112018), Selenium WebDriver with Mocha or PHPUnit<\/p>\n\n\n\n<p><strong>Cypress Example:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code has-background-color has-secondary-background-color has-text-color has-background has-link-color wp-elements-8991d6dadcd6ae092e144231803d0502\"><code>\/\/ cypress\/integration\/loan.spec.js\ndescribe('Loan Application Flow', () => {\n  it('SME can submit a loan request', () => {\n    cy.visit('\/login');\n    cy.get('#username').type('owner1');\n    cy.get('#password').type('password');\n    cy.contains('Sign In').click();\n    cy.contains('New Loan Request').click();\n    cy.get('#institution').select('Bank A');\n    cy.get('#netWorth').type('75000');\n    cy.get('#collateral').attachFile('asset.png');\n    cy.contains('Submit').click();\n    cy.contains('Status: pending').should('be.visible');\n  });\n});<\/code><\/pre>\n\n\n\n<p>Run E2E tests on CI or locally\u2014Cypress offers a fast, reliable runner in your browser.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>A layered approach, linting, unit, integration, component, and E2E, ensures that each part of Laravel\u00a0+ React application remained reliable as we continued to enhance and maintain it.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>While this Loan App system dates back to 2018\u2014built on Laravel 5.x and a React 16 (without Hooks) front-end, it had a structured, layered test suite. In 2018, the popular choices included ESLint and JSCS for linting, PHPUnit for PHP, Jest\u00a0+ Enzyme for React, and Cypress or Selenium for end-to-end. Below, we\u2019ll map out five layers of testing with tools available at the time.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8,12],"tags":[],"class_list":["post-183","post","type-post","status-publish","format-standard","hentry","category-solutions","category-usecases"],"_links":{"self":[{"href":"https:\/\/yulianavarzar.com\/index.php?rest_route=\/wp\/v2\/posts\/183","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/yulianavarzar.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/yulianavarzar.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/yulianavarzar.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/yulianavarzar.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=183"}],"version-history":[{"count":0,"href":"https:\/\/yulianavarzar.com\/index.php?rest_route=\/wp\/v2\/posts\/183\/revisions"}],"wp:attachment":[{"href":"https:\/\/yulianavarzar.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=183"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/yulianavarzar.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=183"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/yulianavarzar.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=183"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}