Skip to content

April of 2022

Projects

Activism

Mentoring

  • New: Introduce the concept and guidelines of mentorship.

    Mentoring is a process for the informal transmission of knowledge, social capital, and the psychosocial support perceived by the recipient as relevant to work, career, or professional development; mentoring entails informal communication, usually face-to-face and during a sustained period of time, between a person who is perceived to have greater relevant knowledge, wisdom, or experience (the mentor) and a person who is perceived to have less (the apprentice).

Coding

  • New: Introduce Cypress.

    Cypress is a next generation front end testing tool built for the modern web.

  • New: Introduce Vite.

    Vite is a build tool that aims to provide a faster and leaner development experience for modern web projects. It consists of two major parts:

    • A dev server that provides rich feature enhancements over native ES modules, for example extremely fast Hot Module Replacement (HMR).

    • A build command that bundles your code with Rollup, pre-configured to output highly optimized static assets for production.

    Vite is opinionated and comes with sensible defaults out of the box, but is also highly extensible via its Plugin API and JavaScript API with full typing support.

  • New: Introduce Vitest.

    Vitest is a blazing fast unit-test framework powered by Vite.

  • New: Display time ago from timestamp.

    Use vue2-timeago

    Install with:

    npm install vue2-timeago@next
    
  • New: Introduce Vuetify.

    Vuetify is a Vue UI Library with beautifully handcrafted Material Components.

  • New: Sum up all Cypress documentation.

    In particular how to:

    • Install it
    • Write tests
    • Setup the tests
    • Do component testing
    • Do visual regression testing
  • New: Truncate text given a height.

    By default css is able to truncate text with the size of the screen but only on one line, if you want to fill up a portion of the screen (specified in number of lines or height css parameter) and then truncate all the text that overflows, you need to use vue-clamp.

  • New: Environment variables.

    If you're using Vue 3 and Vite you can use the environment variables by defining them in .env files.

    You can specify environment variables by placing the following files in your project root:

    • .env: Loaded in all cases.
    • .env.local: Loaded in all cases, ignored by git.
    • .env.[mode]: Only loaded in specified mode.
    • .env.[mode].local: Only loaded in specified mode, ignored by git.

    An env file simply contains key=value pairs of environment variables, by default only variables that start with VITE_ will be exposed.:

    DB_PASSWORD=foobar
    VITE_SOME_KEY=123
    

    Only VITE_SOME_KEY will be exposed as import.meta.env.VITE_SOME_KEY to your client source code, but DB_PASSWORD will not. So for example in a component you can use:

    export default {
      props: {},
      mounted() {
        console.log(import.meta.env.VITE_SOME_KEY)
      },
      data: () => ({
      }),
    }
    
  • New: Deploy with docker.

    And fight to make the environment variables of the docker work, the problem is that these environment variables are set at build time, and can't be changed at runtime by default, so you can't offer a generic fronted Docker and particularize for the different cases. I've literally cried for hours trying to find a solution for this until José Silva came to my rescue. The tweak is to use a docker entrypoint to inject the values we want.

  • New: Testing.

    I tried doing component tests with Jest, Vitest and Cypress and found no way of making component tests, they all fail one way or the other.

    E2E tests worked with Cypress however, that's going to be my way of action till this is solved.

  • New: Add Cypress commands.

    For the functions you write a lot you can use commands in /cypress/support/commands.ts.

    Cypress.Commands.add('getById', (selector, ...args) => {
      return cy.get(`[data-cy=${selector}]`, ...args)
    })
    
    Cypress.Commands.add('getByIdLike', (selector, ...args) => {
      return cy.get(`[data-cy*=${selector}]`, ...args)
    })
    
    Cypress.Commands.add('findById', {prevSubject: true}, (subject, selector, ...args) => {
      return subject.find(`[data-cy=${selector}]`, ...args)
    })
    

    So you can now do

    cy.getById('submit')
    

  • New: Add more ways to select elements.

    • Select by position in list

    Inside our list, we can select elements based on their position in the list, using .first(), .last() or .eq() selector.

    cy
      .get('li')
      .first(); // select "red"
    
    cy
      .get('li')
      .last(); // select "violet"
    
    cy
      .get('li')
      .eq(2); // select "yellow"
    

    You can also use .next() and .prev() to navigate through the elements.

    • Select elements by filtering

    Once you select multiple elements, you can filter within these based on another selector.

    cy
      .get('li')
      .filter('.primary') // select all elements with the class .primary
    

    To do the exact opposite, you can use .not() command.

    cy
      .get('li')
      .not('.primary') // select all elements without the class .primary
    
  • New: Finding elements.

    You can specify your selector by first selecting an element you want to search within, and then look down the DOM structure to find a specific element you are looking for.

    cy
      .get('.list')
      .find('.violet') // finds an element with class .violet inside .list element
    

    Instead of looking down the DOM structure and finding an element within another element, we can look up. In this example, we first select our list item, and then try to find an element with a .list class.

    cy
      .get('.violet')
      .parent('.list') // finds an element with class .list that is above our .violet element
    
  • New: Assert on the content of an attribute.

    cy
      .get('a')
      .invoke('attr', 'href')
      .should('eq', 'https://docs.cypress.io')
    
  • New: Use the content of a fixture set in a hook in a test.

    If you store and access the fixture data using this test context object, make sure to use function () { ... } callbacks both for the hook and the test. Otherwise the test engine will NOT have this pointing at the test context.

    describe('User page', () => {
      beforeEach(function () {
        // "this" points at the test context object
        cy.fixture('user').then((user) => {
          // "this" is still the test context object
          this.user = user
        })
      })
    
      // the test callback is in "function () { ... }" form
     it('has user', function () {
        // this.user exists
        expect(this.user.firstName).to.equal('Jane')
      })
    })
    
  • New: Run only failing tests.

    Cypress doesn't Allow to rerun failed tests but you can use it.only on the test you want to run.

  • New: Make HTTP requests with Vue.

    Compare Fetch API and Axios when doing http requests to external services.

    Explain how to do them with both methods and arrive to the conclusion that if you’re working on multiple requests, you’ll find that Fetch requires you to write more code than Axios, even when taking into consideration the setup needed for it. Therefore, for simple requests, Fetch API and Axios are quite the same. However, for more complex requests, Axios is better as it allows you to configure multiple requests in one place.

    If you're making a simple request use the Fetch API, for the other cases use axios because:

    Axios provides an easy-to-use API in a compact package for most of your HTTP communication needs. However, if you prefer to stick with native APIs, nothing stops you from implementing Axios features.

    For more information read:

  • New: Simulate errors.

    context('Errors', () => {
      const errorMsg = 'Oops! Try again later'
    
      it('simulates a server error', () => {
        cy.intercept(
          'GET',
          '**/search?query=cypress',
          { statusCode: 500 }
        ).as('getServerFailure')
    
        cy.visit('https://example.com/search')
    
        cy.get('[data-cy="search-field"]')
          .should('be.visible')
          .type('cypress{enter}')
        cy.wait('@getServerFailure')
    
        cy.contains(errorMsg)
          .should('be.visible')
      })
    
      it('simulates a network failure', () => {
        cy.intercept(
          'GET',
          '**/search?query=cypressio',
          { forceNetworkError: true }
        ).as('getNetworkFailure')
    
        cy.visit('https://example.com/search')
    
        cy.get('[data-cy="search-field"]')
          .should('be.visible')
          .type('cypressio{enter}')
        cy.wait('@getNetworkFailure')
    
        cy.contais(errorMsg)
          .should('be.visible')
      })
    })
    
  • New: Handling errors doing requests to other endpoints.

    To catch errors when doing requests you could use:

    try {
        let res = await axios.get('/my-api-route');
    
        // Work with the response...
    } catch (error) {
        if (error.response) {
            // The client was given an error response (5xx, 4xx)
            console.log(err.response.data);
            console.log(err.response.status);
            console.log(err.response.headers);
        } else if (error.request) {
            // The client never received a response, and the request was never left
            console.log(err.request);
        } else {
            // Anything else
            console.log('Error', err.message);
        }
    }
    

    The differences in the error object, indicate where the request encountered the issue.

    • error.response: If your error object has a response property, it means that your server returned a 4xx/5xx error. This will assist you choose what sort of message to return to users.

    • error.request: This error is caused by a network error, a hanging backend that does not respond instantly to each request, unauthorized or cross-domain requests, and lastly if the backend API returns an error.

      This occurs when the browser was able to initiate a request but did not receive a valid answer for any reason.

    • Other errors: It's possible that the error object does not have either a response or request object attached to it. In this case it is implied that there was an issue in setting up the request, which eventually triggered an error.

      For example, this could be the case if you omit the URL parameter from the .get() call, and thus no request was ever made.

  • New: Use Flexbox with Vuetify.

    Control the layout of flex containers with alignment, justification and more with responsive flexbox utilities.

    Note

    "I suggest you use this page only as a reference, if it's the first time
    you see this content, it's better to see it at the
    [source](https://vuetifyjs.com/en/styles/flex) as you can see Flex in
    action at the same time you read, which makes it much more easy to
    understand."
    

    Explain how to use:

  • New: Illustrations.

    You can get nice illustrations for your web on Drawkit, for example I like to use the Classic kit.

  • Correction: Correct the way to test for an attribute of an html element.

    cy
     .get('a')
       .should('have.attr', 'href', 'https://docs.cypress.io')
       .and('have.attr', 'target', '_blank') // Test it's meant to be opened
       // another tab
    
  • New: Sending different responses.

    To return different responses from a single GET /todos intercept, you can place all prepared responses into an array, and then use Array.prototype.shift to return and remove the first item.

    it('returns list with more items on page reload', () => {
      const replies = [{ fixture: 'articles.json' }, { statusCode: 404 }]
      cy.intercept('GET', '/api/inbox', req => req.reply(replies.shift()))
    })
    

Learning to code

  • New: Introduce guidelines to learn how to code.

    Learning to code is a never ending, rewarding, frustrating, enlightening task. In this article you can see what is the generic roadmap (in my personal opinion) of a developer. As each of us is different, probably a generic roadmap won't suit your needs perfectly, if you are new to coding, I suggest you find a mentor so you can both tweak it to your case.

Frontend developer

  • New: Introduce guidelines to learn how to become a frontend developer.

    This section is the particularization of the Development learning article for a frontend developer, in particular a Vue developer.

    A Front-End Developer is someone who creates websites and web applications. It's main responsibility is to create what the user sees.

    The basic languages for Front-End Development are HTML, CSS, and JavaScript. Nowadays writing interfaces with only the basic languages makes no sense as there are other languages and frameworks that make better and quicker solutions. One of them is Vue, which is the one I learnt, so the whole document will be focused on this path, nevertheless there are others popular ones like: Bootstrap, React, jQuery or Angular.

    The difference between Front-End and Back-End is that Front-End refers to how a web page looks, while back-end refers to how it works.

Python

Profiling

  • New: Added memray profiling tool.

    memray looks very promising.

Python Snippets

  • New: Get the attribute of an attribute when sorting.

    To sort the list in place:

    ut.sort(key=lambda x: x.count, reverse=True)
    

    To return a new list, use the sorted() built-in function:

    newlist = sorted(ut, key=lambda x: x.body.id_, reverse=True)
    

Frontend Development

Git

  • New: Introduce git and how to learn it.

    Git is a software for tracking changes in any set of files, usually used for coordinating work among programmers collaboratively developing source code during software development. Its goals include speed, data integrity, and support for distributed, non-linear workflows (thousands of parallel branches running on different systems).

Park programming

  • New: Introduce the park programming concept.

    Park programming is as you may guess, programming in parks. It includes guidelines on:

    • How to park program
    • Finding the best spots
    • Finding the best times

CSS

  • New: CSS Flexbox layout.

    The Flexbox Layout aims at providing a more efficient way to lay out, align and distribute space among items in a container, even when their size is unknown and/or dynamic.

Javascript

Javascript snippets

  • New: Round a number.

    Math.round(2.5)
    
  • New: Remove focus from element.

    document.activeElement.blur();
    
  • New: Concatenate two arrays.

    const arr1 = ["Cecilie", "Lone"];
    const arr2 = ["Emil", "Tobias", "Linus"];
    const children = arr1.concat(arr2);
    

    To join more arrays you can use:

    const arr1 = ["Cecilie", "Lone"];
    const arr2 = ["Emil", "Tobias", "Linus"];
    const arr3 = ["Robin"];
    const children = arr1.concat(arr2,arr3);
    
  • New: Check if a variable is not undefined.

    if(typeof lastname !== "undefined")
    {
      alert("Hi. Variable is defined.");
    }
    
    feat(vue_snippets#Run function in background): Run function in background

    To achieve that you need to use the javascript method called setInterval(). It’s a simple function that would repeat the same task over and over again. Here’s an example:

    function myFunction() {
        setInterval(function(){ alert("Hello world"); }, 3000);
    }
    

    If you add a call to this method for any button and click on it, it will print Hello world every 3 seconds (3000 milliseconds) until you close the page.

    In Vue you could do something like:

    <script>
    export default {
      data: () => ({
        inbox_retry: undefined
      }),
      methods: {
        retryGetInbox() {
          this.inbox_retry = setInterval(() => {
            if (this.showError) {
              console.log('Retrying the fetch of the inbox')
              // Add your code here.
            } else {
              clearInterval(this.inbox_retry)
            }
          }, 30000)
        }
      },
    

    You can call this.retryGetInbox() whenever you want to start running the function periodically. Once this.showError is false, we stop running the function with clearInterval(this.inbox_retry).

Operating Systems

Linux

Linux Snippets

elasticsearch

Other

  • Reorganization: Reorder the blue book navigation panel.
  • New: Sum up all the VueJS documentation.
  • New: Troubleshoot Failed to resolve component: X.

    If you've already imported the component with import X from './X.vue you may have forgotten to add the component to the components property of the module:

    export default {
      name: 'Inbox',
      components: {
        X
      }
    }